Johan Sørensen

Modern modern Objective-C

With the arrival of LLVM and the modern runtime Objective-C has been having some steady progress and while it’s not really moving so fast that it’s hard to stay up to date, some habits may be hard to change.

Below is a far from complete list of things that I look out for on the syntax-level that I consider to be modern Objective-C. You, the seasoned cocoa developer, know all of these and probably agree with most of them, you might even doze off reading it as they’re so incredibly obvious. I’ve left out some of the most obvious ones, such as ARC and blocks.

Synthesized-by-default properties

Available with the LLVM Compiler 4.0 there’s no need for @synthesize in the implementation when declaring properties. Note that some property declarations together with your own getters or setters may require you to add a synthesized instance variable, readonly properties with your own getter method for instance.

Instance variables prefixed with underscore

The default auto-synthesis of properties creates instance variables prefixed with an underscore. Seconded only by dot-notation this has been one of most debated tiny issues in the community. I don’t think we’ll ever get a more clear answer that prefixing instance variables with an underscore is perfectly fine.

Instance variables in the implementation

Internal instance variables should be declared at the start of the @implementation block. This will Keep the internal instance variables out of your public headers, even if you and your colleagues the only one seeing them. If you really feel that some instance variables should be part of your public API, then consider exposing them using properties instead.

Header files represent the clean public API

The header file should only represent properties and methods which you consider part of your objects public API, this makes it easier for everyone else to see how the object is supposed to be used without being distracted by your internal object logic. With instance variables in the implementation file, there’s no point in exposing them to the world. If you need to declare internal “inter object” methods, use a separate header file (MyClass+Private.h for instance) that your subclasses or fellow objects can import.

However, one thing I struggle a bit with to fit into this regime is IBOutlets. Not the delegate, dataSource or other outlets I really want to be public API, but your average textfield connected to a view controller. These are usually very much internal API, yet I still hook them up to properties in my header file rather than in a private class extension in the implementation file. I suspect the biggest reason is that Xcode’s assistant defaults to the corresponding header file when editing a nib file, but it also makes it easier for me to see if all outlets are hooked up and what they’re named.

Number, array and dictionary literals

Should be a no-brainer if your deployment target supports it. Less typing, less repetition. Apart from the @ avalanche.

NS_ENUM

I’m still warming up to this one as it’s new in the 10.8 and [redacted] SDKs. You’d declare your enumeration constants like this:


typedef NS_ENUM(NSUInteger, MyClassSetting) {
	MyClassSettingAwesome,
	MyClassSettingDull
};

The upside is you’ll get additional warnings (with -Wconversion) if you pass something not in the enum to a type, but even more useful (depending on your viewpoint) is that Xcode’s autocomplete will will be scope to the values of the enum. For more information on these fixed underlying type enums (which is what the macro expands to) see Mark Dalrymples post on the subject of enums.

“Private” methods without a private class extension interface

With LLVM you don’t need to define private/internal methods in a private class extension interface as LLVM’s two-pass compiler will figure it out, regardless of whether those “undeclared” methods are implemented before or after the location in the implementation file where you’re calling them.

Related result types for initializers

LLVM introduces the instancetype type, which you’d typically use as the return type of your initializers rather than id. In return you can additional checking that your initializer actually return what you’d expect (nil or an instance of your class’ static type).

Apple has a availability index on some of these features.