MacKuba

🍎 Kuba Suder's blog on Mac & iOS development

What's new in ObjectiveC

Categories: Cocoa Comments: 0 comments

This post is mostly based on a presentation I’ve done on the last CocoaHeads meeting in Kraków. (If you’re a Cocoa developer and you’re in Kraków on a 2nd Thursday of a month, come say hi!)

Thea idea was basically to collect all the things that have changed in ObjC in the recent years in one place. There were quite a few of these (which is a great thing!) and it’s sometimes hard to remember all of them, especially if you’re trying to update the code of an older project to newer coding style. Hopefully you will also find something here that you didn’t know about before.

LLVM to the rescue

It used to be rather painful to write code in ObjectiveC. I mean, if you’ve been doing it for years you probably got used to it; but for people that switch from other languages, especially dynamic ones like Python or Ruby, it was a torture. Not only you have to write all those scary square brackets, manage the memory manually (which was a constant source of crashes), type those method names that don’t fit in one line, but you can’t even create an array or a hash easily? That was just madness.

Luckily, a lot has changed since I started learning ObjC a few years ago, and a lot of the things I used to complain about at first are no longer true. It’s still not as pleasant as coding in Ruby (and it will never be), but it’s much less painful than it was before.

Most of these changes were made possible by investing time to develop LLVM, a new compiler infrastructure that has now completely replaced GCC and allowed Apple to add features to the language much faster than before. It took a few years, it wasn’t always easy (and it’s still a minor annoyance at times), but it was definitely worth it.


Instance variables for @property

Requires: modern runtime

(What’s a modern runtime, you might ask? Check out Apple’s docs for an explanation, but in short, OSX has had that since 10.5 (but only on 64-bit machines) and iOS has had that from the beginning.)

This one’s fairly old, but I’ve included it for completeness. Previously, if you declared a @property in a class, you also had to declare a matching ivar (instance variable), like this:

@interface MyKlass {
  NSMutableArray *list;
}

@property NSMutableArray *list;

@end

Actually, you might still need to do this if you want to support 32-bit Macs (but there aren’t a lot of these left around). This was rather annoying and repetitive, especially since you also had to declare the same variable in @synthesize and in dealloc, which means that every new variable had to be added in 4 different places manually. That’s definitely not DRY at all.

If you only support modern runtimes, you can now skip the ivars if you have a @property:

@interface MyKlass

@property NSMutableArray *list;

@end

Blocks

Requires: OSX 10.6 / iOS 4.0

Blocks are what you might know as closures or lambdas from other languages – anonymous functions defined inline in code, capturing the context in which they’re created. Just like in other languages, they can be used e.g. for callbacks to be called when some task is completed (very useful in network handling code), functional-style array operations (map/select/reduce) or for concurrency (NSOperation).

The syntax is kind of awkward, but it’s mostly just in the method definitions (the more arguments, the worse it gets):

- (void) load: (NSString *) url callback: (void (^)(NSString *)) callback {
  NSString *response = [connector requestTo: url];
  callback(response);
}

The method you see above accepts a callback block that takes an NSString and returns void. To simplify such declarations, you might want to use a typedef to give a name to this type of block:

typedef void (^NetworkCallback)(NSString *);

- (void) load: (NSString *) url callback: (NetworkCallback) callback;

However bad this looks in a statically-typed language, it’s still worth it because it often lets you do things that were either not possible before or required much more code to achieve the same effect. And passing blocks to a method defined somewhere else is a bit simpler:

[list enumerateObjectsUsingBlock: ^(id obj, NSUInteger i, BOOL *stop) {
  NSLog(@”#%d = %@”, i, obj);
}];

enumerateObjectsUsingBlock: is a built-in method in NSArray that acts more or less like Ruby’s Array#each or JavaScript’s Array#forEach. There aren’t many other such methods in the Foundation classes, but you can easily add some yourself.


Private variables in @implementation

Requires: Xcode 4.2 + LLVM + modern runtime

Private variables were previously declared in the interface file (*.h), like this:

// MyKlass.h

@interface MyKlass {
  NSMutableArray *list;
}

@end

It’s not a big problem really, but the interface file is meant for the users of your class, and ivars are usually only used internally. It makes much more sense then to put them in the implementation file (*.m).

Since Xcode 4 (with LLVM) we were able to put the ivars in a class extension in the *.m file:

// MyKlass.m

@interface MyKlass () {
  NSMutableArray *list;
}

@end

@implementation MyKlass
// ...
@end

I never liked class extensions though, they somehow make the implementation file more messy by adding a second top-level block. Fortunately, we don’t really need them anymore since now we can just put the ivars in the @implementation block:

// MyKlass.m

@implementation MyKlass {
  NSMutableArray *list;
}

// ...

@end

Automatic Reference Counting (ARC)

Requires: Xcode 4.2 + OSX 10.6 64-bit / iOS 4.0

This was a huge change. Since version 10.5 OSX has had a garbage collector, but on iOS you had to manage the memory manually, which was a major pain in the ass (even though it got better if you remembered all the rules and used the Xcode analyzer to detect bugs). We were waiting for the day when iOS finally gets a GC too, but instead we got something better.

What is ARC? It’s a compiler feature that basically inserts all the memory management method calls in the right places for you automatically. From the developer’s perspective it’s very similar to a GC, but it usually works slightly faster since there’s no overhead to run the GC in the background when memory runs out. There’s just one requirement – you have to follow all the rules Xcode requires from you, so that it knows what it’s supposed to do for you.

Thanks to ARC, a method that used to look like this:

- (NSArray *) views {
  NSMutableArray *arr = [[NSMutableArray alloc] init];
  UIView *view = [[UIView alloc] initWithFrame: frame];
  [arr addObject: view];

  [view release];
  return [arr autorelease];
}

Now looks like this:

- (NSArray *) views {
  NSMutableArray *arr = [[NSMutableArray alloc] init];
  UIView *view = [[UIView alloc] initWithFrame: frame];
  [arr addObject: view];

  return arr;
}

There’s no need to call retain, release or autorelease (in fact you’re not allowed to call them yourself). This also greatly simplifies dealloc methods – now most of the time you don’t need them at all (unless you have some custom code there apart from release and [super dealloc] calls).

A funny twist in the story is that GC is deprecated on OSX 10.8 – so clearly ARC is the way forward on all Apple platforms.

You can read everything about converting your code to ARC in Apple’s documentation.


Forward method declarations

Requires: Xcode 4.3

Everyone that starts coding in ObjC encounters this error sooner or later:

@implementation MyKlass

- (void) bar {
  [self foo];   // <-- Xcode: WTF is this?
}

- (void) foo {
  // ...
}

Ok, it’s not exactly what Xcode says, but you get the idea: inside your methods you can only call methods of the same class that are either defined earlier in the file, or at least declared in an interface. So you either add a declaration to the class extension (which I hate), or to the public interface (which is kind of wrong), or you start moving methods around, messing up your original order, hoping that it’s enough for Xcode to shut up (which is even more stupid).

Since Xcode 4.3 this is fortunately a thing of the past. You can now order your private methods as you like.


Automatic @synthesize

Requires: Xcode 4.4 + modern runtime

Remember how I wrote that you had to add every new variable in 4 places? Now it’s finally down to 1, because you don’t even have to declare @synthesize for properties.

So if you have an interface like this:

@interface MyKlass

@property NSString *name;

@end

Your implementation can now look like this, and the name property will be synthesized automatically:

@implementation MyKlass

- (void) printName {
  NSLog(@”%@ %@”, _name, self.name);
}

@end

Notice how the ivar’s name starts with an underscore (if you want a different name, you still need to use @synthesize). For me this seems like a slight hint that you should rather access it through the property whenever possible, even inside the class (that’s just my personal interpretation though).


ObjC literals

Requires: Xcode 4.4

I’ve been waiting for this since I wrote my first line of ObjC, and I’m pretty sure I wasn’t alone at this. We can now finally create NSArrays, NSDictionarys and NSNumbers like in any other language, without having to call methods with very long names or resorting to C macros and other magic.

To wrap numbers or booleans in NSNumber (e.g. to insert them into an array), you had to call one of these:

[NSNumber numberWithBool: YES]
[NSNumber numberWithInt: 1]
[NSNumber numberWithFloat: x]

To create an array, you had to call this method (and remember to add a nil at the end!):

[NSArray arrayWithObjects: @”twitter”, @”facebook”, @”github”, nil]

Creating a dictionary was even worse, because the order of key-value pairs was also inverted. And if you wanted to include numbers or booleans in the dictionary, it was getting really complex:

[NSDictionary dictionaryWithObjectsAndKeys:
  @”Kuba”, @”firstName”,
  @”Suder”, @”lastName”,
  [NSNumber numberWithInt: 30], @”age”,
  nil]

Now you can use @[] to create arrays, @{} to create dictionaries and prepend @ to numbers to turn them into NSNumbers:

@1, @2.5, @YES, @(x)

@[@”twitter”, @”facebook”, @”github”]

@{ @”firstName”: @”Kuba”, @”lastName”: @”Suder”, @”age”: @30 }

Looks much better, doesn’t it? :)


Array & dictionary subscripting

Requires: Xcode 4.4 + OSX 10.6 64-bit / iOS 5

Another extension to NSArray and NSDictionary syntax is that you can also look up and insert objects into them using a familiar syntax known from other languages instead of having to call getter and setter methods explicitly.

Instead of:

[array objectAtIndex: 2]
[array replaceObjectAtIndex: 0 withObject: @”first”]

You can now do:

array[2]
array[0] = @”first”

And the same thing for dictionaries – before:

[dictionary objectForKey: @”id”]
[dictionary setObject: @”jsuder” forKey: @”author”]

After:

dictionary[@”id”]
dictionary[@”author”] = @”jsuder”

Behind the scenes the compiler still calls appropriate methods to find or insert elements. What’s more, if you implement these methods in your own classes – even ones completely unrelated to NSArray and NSDictionary – you can make them act like arrays and dictionaries and use the same syntax on them. Note that these aren’t exactly the same methods you used to use with NSArray and NSDictionary, they’re new methods that were added specially for this purpose.

For example, if you have a list-like object, you can access it like an array if you define objectAtIndexedSubscript::

- (id) objectAtIndexedSubscript: (NSUInteger) i {
  return list[i];
}

NSLog(@”record = %@”, collection[5]);

And if you have an object that can look up some internal elements using a key, you can make it work like a dictionary:

- (id) objectAtKeyedSubscript: (id) key {
  for (Node *node in tree) {
    if ([node.name isEqual: key]) {
      return node;
    }
  }

  return nil;
}

NSLog(@”node = %@”, xmlDocument[@”date”]);

You can find a more complete documentation about literals and subscripting on the LLVM site.

There’s also a trick you can use to make subscripting work on iOS 4.3 (normally it doesn’t work, because the new lookup/insertion methods weren’t originally present in NSArray in NSDictionary) – more info here.


Extras from Foundation

Finally, I wanted to include some additions to the Foundation framework that aren’t technically syntax extensions, but are still useful things that you might have missed.

JSON parsing

Requires: OSX 10.7 / iOS 5.0

If you wanted to parse JSON data in earlier versions of iOS/OSX, you had to use one of the open source libraries available, like TouchJSON, YAJL, JSONKit etc. (see my benchmark comparing their performance). Apple now includes an NSJSONSerialization class in the SDK that handles JSON parsing and serialization, so you don’t need any third party libraries for that:

[NSJSONSerialization JSONObjectWithData: data
                                options: 0
                                  error: &err];

Regular Expressions

Requires: OSX 10.7 / iOS 4.0

Just like with JSON parsing, if you needed to use regular expressions, you probably had to include RegexKit or RegexKitLite in your project. Now there’s a built-in NSRegularExpression class in Foundation that you can use for this purpose (though it has less features and a less friendly syntax):

NSRegularExpression *re =
  [NSRegularExpression regularExpressionWithPattern: @”^\\w+@\\w+(\\.\\w+)+$”
                                            options: 0
                                              error: &err];

[re matchesInString: email options: 0 range: NSMakeRange(0, 20)];

That’s about it. If I got anything wrong, please let me know. As for the iOS/OSX version requirements, they might not always be 100% correct – I’ve based them on Apple’s documentation, this ObjC Availability Index page and comments from StackOverflow, and there was sometimes conflicting information about this in different places, so if you’re not sure, you should just try for yourself what works and what doesn’t.


Leave a comment

*

*
This will only be used to display your Gravatar image.

*

What's the name of the base class of all AppKit and UIKit classes?

*