Saturday, October 13, 2012

Clang Language Extensions: instancetype

Clang added several features to the Objective-C language. One of these features is the ‘instancetype’ keyword. When creating objects, we frequently use methods in the alloc and init families. They have a return type of id, but the compiler knows that they will return an object that matches the class being used. For example, [[NSString alloc] init] returns an NSString and [[NSMutableString alloc] init] returns an NSMutableString.

There are several methods that will automatically infer the return type from the method name. They must follow standard camel-case naming and start with the following words:

For class methods:
        alloc
        new

For instance methods:
        autorelease
        init
        retain
        self

For any methods that do not follow this naming convention, we use the keyword instancetype. Let’s say we have the following objects:

@interface Animal : NSObject

+ (instancetype)createAnimalWithName:(NSString *)name;

@end

@interface SnowLeopard : Animal

- (void)pounce;

@end

@interface MountainLion : Animal

- (void)roar;

@end

Now let’s say we create an object and call a method on it like so:

[[MountainLion createAnimalWithName:@"Maxwell"] roar];

If +createAnimalWithName: returns id or instancetype, then the compiler accepts this just fine. If it returns an Animal object, then the compiler gives the warning: “Animal may not respond to roar.”

So, when does instancetype have an advantage over id? Let’s say we do this instead:

[[MountainLion createAnimalWithName:@"Maxwell"] lastObject];

A MountainLion is clearly not an NSArray; however, the compiler will happily accept this if +createAnimalWithName: returns an id. It’s not until we run the app that the we find the error when our app crashes due to an unrecognized selector method exception.

In summary, the instancetype keyword helps the compiler help you know when something is wrong. If for any reason you need to know if the compiler supports this feature, you can use the macro __has_feature(objc_instancetype).

If you want to learn more about instancetype and other Clang features, check out the Clang docs.