Working on an app last week, I needed a way to respond to rotation events in a view controller. Since iOS8, the rotation APIs in UIViewController
are deprecated:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(2_0,8_0, "Implement viewWillTransitionToSize:withTransitionCoordinator: instead");
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation NS_DEPRECATED_IOS(2_0,8_0);
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration NS_DEPRECATED_IOS(3_0,8_0, "Implement viewWillTransitionToSize:withTransitionCoordinator: instead");
As you can see, they want you to use viewWillTransitionToSize:withTransitionCoordinator:
instead.
So, no problem, we'll just implement that method.
Update: I'd like to stress this a little more: the reason they've changed these behaviors is for a reason. Your app mostly likely is way better off using adaptive layout using size classes, Auto Layout and manual corrections using the new transition callbacks.
Now, the only thing is: what if you need to know those "toInterfaceOrientation" or "fromInterfaceOrientation" value from the old APIs?
Let me introduce: SwiftyAs. It's a tiny little library to provide sort of the same functionality as as?
from Swift in Objective-C. Let me explain...
Brent Simmons touches on the use of abbreviations in Cocoa. I've noticed this behaviour too, and other uncocoalike things too. This is especially apparant in code of devs coming from other programming language/platforms.
For the project I'm working on we ran into a performance issue on iPhone4 where an interaction would lock up the phone for a few seconds. It ran fine on iPhone5 and in the Simulator, but there was a severe hangup in on the older device. Investigation in Instruments revealed to problem to be autolayout. A lot of time (>3 seconds) was spent recalculating layout.
So I first hunted for [view layoutIfNeeded]
calls, replacing them by [view setNeedsLayout]
where applicable (sometimes you actually want to layout immediately if you need to do more stuff based on the layout results, but this is rarely the case). To no real avail, the issue remained extremely slow.
Digging in further, I found that two different call trees were doing autolayout of a certain part of the screen at the same time. This was all happening on the main thread which explained the lockup (no surprises there though). But in the timespan of the 2 seconds Instruments reported where (the major part of the) lockup was, there were two blocks where setting a label caused at least 800ms of autolayout calculations. So that's 1.6s accounted for. Which seemed like a good starting point to optimize.
The code was just setting properties (in this case: a title label and a response handler block), but they both touched the same label twice. I pondered on coalescing the two properties in one method but it seemed like an unsatisfying solution. And so I decided to copy a pattern Apple uses too regarding UI: the 'setNeedsLayout' pattern.
A blogpost by Klaas Pieter Annema is doing the rounds on twitter lately. It appears the builder pattern is quite new to iOS devs since everybody is raving about it. In my own humble opinion I do think it is a bit convoluted for what it's worth.
The followup post by Joris Kluivers makes better use of existing classes: NSURLComponents
becomes the builder for an NSURL
, and given that these classes are already present and used in other use-cases, the builder pattern makes a lot of sense this way.
But I still feel that rolling just a builder class to construct an object is a bit overkill. But it turns out you don't need two classes: you just need to leverage another feature of Objective-C: protocols.
Xcode 5.0 introduced an interesting new feature: Quick Look for variables. Basically, it lets you inspect variables and their contents in a graphical way. This allows for interesting ways of viewing the state of your app.
I've been using the feature quite a bit: it's a great way to inspect images or colors you're using in your app, for example. Works great on attributed strings, too.
Xcode 5.1 improves the feature even further with the addition of debugQuickLookObject
. This method allows you to provide quick look content for any of your own classes. A bit like debugDescription
but more advanced. I haven't had the time to look further into it.
I was listening to the most recent Debug episode, the one featuring the ever apologetic @caseyliss talking about C#. It's another great episode (but most of the Debug episodes are great - I love the interaction of @gte with his guests). I was particularly interested in this one since I have a similar background: I spent most of my working days on a Microsoft platform and produced a bucketload of C# code (ever since it came out early 2000). Since late 2010 I've been mostly dabbling in Objective-C on the iOS platform. So I was quite curious on what Casey had to say.
While I'm not going to rehash everything here (go listen to the podcast), I agreed with most of it. I do think he forgot an important feature of generics and c# in general: "compile time breakage".
And a follow-up post for this one. Already!
I forgot about it, but @pjaspers reminded me that we actually did something similar to this using "regular" language constructs.
What you could do:
#include "Protocol+Implementation.m"
in
the class' implementation file. You read that right: thats an include and not an import.Yup. Categories for protocols. You heard that right. It started with me asking about it on twitter:
This question caused much confusion. "How is that even possible?" "Categories are used to extend existing classes, surely how can you extend a protocol?"
Just a quick tip, this one.
In Objective-C, like in every strongly typed language, sometimes you need to cast something to another type:
ModalViewController* modalController = (ModalViewController*)self.parentViewController;
Well, you don't have to, but you get a pesky warning if you don't. The code will work fine, but warnings are ugly: