Aleksandar • Vacić

iOS bits and pieces

How to support landscape mode in your app on iPhone 6

In your AppDelegate file, add this:

- (NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {

  if (window && window.bounds.size.width <= 320)
      return UIInterfaceOrientationMaskPortrait;
  return UIInterfaceOrientationMaskAll;

This will force portrait only in iPhone 5s or older and enable all orientations in iPhone 6 and up and all iPads.

Reconcilable Differences

Oh man… I am siting here in my favorite coffee shop listening to this awesome podcast featuring two great people. Barely holding my tears. These guys are so obviously the same age as me. They speak about PPP, SLIRP, 2400 baud modems and the ecstasy of being directly connected to the dawn of the Internet. Those first, crazy long email addresses featuring five sub-domains, personal URLs with ~username, living online either at home (lucky bastards!) or at the University terminal room. Learning HTML with Navigator 1.1 , Javascript and frames with 2.0. And all that.

Oh, wow. I had “I was there, I did that too!” moments, like 20 times in the last hour.

And more than anytime in the last several years, I can’t help feeling absolute rage about how much we here in Serbia wasted those moments in the 90s. So much wasted.

WatchKit 1.0 redux

At recent Code Conference, Jeff Williams, Apple’s VP of Operations, announced that on WWDC 2015 Apple will present what is colloquially called WatchKit 2.0, a set of SDK to create “native”1 Watch apps.

My first reaction was: “WTH..? Already?!” That’s way, way too fast.

WatchKit 1.0 was presented last November, but devices using it started arriving to owners a mere month ago and there’s still a significant backlog of orders. Thus I’m sure there are many users and more importantly developers who don’t have the watch yet. I got my watch due to lucky set of events on Apr 27th and since then I spent almost 3 full weeks trying to get Run 5k’s watch app to work reliably and with a bit of flair in the UI. It’s now waiting for review and you can see this short demo on Vimeo:

Creating watch apps in 1.0 is an exercise in patience, to say the least. There has never been a larger gap between working on the Simulator and with real device. I can pretty confidently say that Simulator is good only for the layout and basic workflow but all other development should be done using the real device. You simply don’t see many of the possible issues in the Simulator.
Some examples: in the Simulator there’s no way to even try a very real scenario where customer exists your app down to the app grid then immediately goes back to the app. Or the screen goes black and once you tap it you are on the watch face, not in your app. Or “activate on wrist raise” scenario. Etc.

I was more than a little embarrassed just how unreliably original Run 5k watch app works in various usage scenarios. All of those scenarios worked perfectly in the Simulator.

Thus this upcoming version is about 90% new code. This post summarizes what I learned and we’ll see was this all for nothing when WatchKit 2.0 is presented.

Removing CADisplayLink from run loop

Do not use this

[self.displayLink removeFromRunLoop:NSRunLoop.mainRunLoop

Instead use this:

[self.displayLink invalidate];

Reason, from documentation:

Removing the display link from all run loop modes causes it to be released by the run loop. The display link also releases the target.

It safely releases all references and removes itself.

I was recently chasing a very strange rare crashes in Run 5k, my app with 1000s of daily users. It would SIGSEGV crash inside the CADisplayLink’s selector for about 100 or them during the week. Making the code change above solved all those issues.

My guess is that removeFromRunLoop:forMode: would enter a race condition with the call to the target’s selector method in some obscure situation. Who knows.