Woohoo ! Generics in Objective C

Since writing this quick late night post, I've written a better one here. Please check that out.


Original post

This is very preliminary, but I was just so excited by it when I found it in the release notes I had to write this!

Something I always liked in Java was Generics which allow us to create classes which can act 'generically' against one or more unknown types, yet when used, can be passed a specific type to enforce the type of what they work with.

Well now with the latest XCode 7, we finally have the concept of generics being applied. Lets look at what I'm talking about and how they can help you.

Generic Collections

Here's some sample code that creates a mutable set:

NSMutableSet *mySet = [[NSMutableSet alloc] init];
[mySet addObject:@"abc"]; 
[mySet addObject:@1];

As you can see, the set is quite happy to accept objects of any type. In this case a string and an integer. Sometimes we want this, but sometimes this open approach can lead to bugs where we accidentally store the wrong type.

With the new Xcode 7 we get the ability to apply a specific type like this:

NSMutableSet<NSString *> *mySet = [[NSMutableSet alloc] init];
[mySet addObject:@"abc"]; 
[mySet addObject:@1]; // <-- Will now fail to compile.

The <NSString *> declaration defines that the NSMutableSet will ONLY work with NSString * objects. All the methods that would normally accept objects of any type, now only accept NSString pointers.

When you build this, you will get
error: incompatible pointer types sending 'NSInteger *' to parameter of type 'NSString * __nonnull' on the second addObject: line.

The great thing about this is that it's the same class. We didn't have to code up a NSMutableSet that only takes string objects. Suddenly the class is both open to handling objects of any type, yet if we specify a generic type, will only accept objects of that type.

You may also notice that it's exactly the same syntax as Java uses. That's a real help to those of us familiar with it's syntax.

Let look at a dictionary with generic types being specified:

NSMutableDictionary<NSString *, NSNumber *> *generics = [[NSMutableDictionary alloc] init];
generics[@"abc"] = @12;
generics[@"def"] = @"xyz"; // <- Fails to compile.

Brilliant! Now lets take a look at creating generic classes.

Generic classes

So how can we created our own classes that can act like Apple's classes. SO far I've been able to do this (Despite what the doc says) by declaring a class like this:

@interface MyClass<__covariant T> : NSObject
-(T) doSomethingWith:(T) aTypeT;
@end

@implementation MyClass
-(id) doSomethingWith:(id) aTypeT {
    return aTypeT;
}
@end

This works exactly the same as Apple's collection classes and produces errors as they do when the wrong type is passed. It appears that the interface can be declared using generics, but the implementation cannot and must have a valid type wherever the generic type is used.

Further I found that I could apply bounds to a generic type in a similar fashion to how Java does things. So declaring the interface like this:

@interface MyClass<__covariant T:NSNumber *> : NSObject
-(T) doSomethingWith:(T) aTypeT;
@end

Meant that the compiler would now insist that any type used as the generic has to extend NSNumber. Also the implementation could now become:

@implementation MyClass
-(NSNumber *) doSomethingWith:(NSNumber *) aTypeT {
    return aTypeT; 

} @end

Enjoy.


Comments powered by Disqus