Generics in ObjC

“Why would I want generics?”

you may ask. And for good reason: often we use classes that works against arbitrary types. Apple makes it all the time. Just look at the NSArray or NSDictionary classes for example.
But lets see the benefits of using generics:

  • When you use arbitrary type, there is nothing to prevent you to accidentally use a wrong object type. For example adding an NSString to a collection, but expecting an object when you retrieve the data. This may lead to nasty bugs, even crashes, that may be revealed at runtime only.
  • Using generics enables code completion
  • Using generics makes the object’s interface visible without cast. For example if I have a class named Foo that has a property named ‘status’, you could access that property for anĀ  simply by calling: [array objectAtIndex:index].status;

Apple’s generics

In XCode 7 Apple enabled generics on its collection classes. Lets say we want to store Foo objects in a collection. Without generics the code would look like this:

As you can see, I added an invalid object to the collection. But I will notice the error only at runtime. So lets see the same collection using a generic implementation:

I added the made the same mistake, but this time I get a compiler warning: “Incompatible pointer types sending ‘NSString *’ to parameter of type ‘Foo'”. So I will know about my mistake at compile time. (If you treat warnings as errors you will have an error at compile time. This is a safer approach, since you may ignore warnings. You can turn this option on in your build settings.) As I mentioned it earlier, you can use Foo’s properties and methods without casting it to Foo:

For NSSet it is working the same. NSDictionary also supports generics, but you have to specify the key’s type too:

Custom generics

But why stop here? If you think about, probably it is a good idea to extend the use of generics to non-collection classes too. Whenever you have to use arbitrary objects, probably it is a good idea to implement it as a generic class. So where do we start? Apple’s documentation doesn’t mention anything about custom generic classes in Objective C. Well, they already implemented it in their collection classes, so why don’t we start it there? All we have to do is copy their implementation, and we should be set.
I made a quick test project to see it’s working. The class is called: ‘MySmartDevices’. It is a very simple class. All it does is storing ‘my devices’ by their name. Here is the header file:

Between the angle brackets after the name of the class you see the placeholder for type. You can specify more than one placeholders here if needed. This basically could be anything. In Java it is usually ‘T’. I chose ObjectType for two reasons: first it is a descriptive name for it, and second this is what Apple uses.

So when I want to use this class with a specific type, I just replace the placeholder with an actual type:

The ‘__covariant’ keyword is optional. It makes the generic class covariant on its type argument. So for example if I add this keyword, I will be able to do this:

The implementation file looks the same as without generics:

Unfortunately I didn’t find any way to use the same placeholder for type in the implementation file too. So we still have to use id for arbitrary types in the implementation.

Restricting Generics

But what if I don’t want to allow arbitrary types, I want to restrict to some types? Fortunately we have a solution for that too:

where Device is an actual type. You could even modify the implementation to use this type instead of id in your methods. Also an interesting thing is that you can use protocols as well:

In other words whatever class is specified when using this class, it must implement the ‘Apple’ protocol.

Of course, you can also use protocols when declaring an instance of a Generic class: