Objective-C Generics

Sure, last year WWDC was all about Swift. That’s a given. After progressing to 2.0, becoming open source, and introducing protocol extensions and a new error handling API, Apple’s young child has grown into a heavy-hitter and deservedly captured the audience’s attention. But in the world of iOS development, good old Objective-C is still in the game, and WWDC 2015 brought a notable new feature. Without further ado, Ladies and Gentlemen, let me talk a little about Objective-C Generics.

Take a look at this code:

Nothing complicated, we have a class, Person, with three properties. Although it should be a struct, for the purpose of this blog post (a comparison with Objective-C) we decided to use class. We have the property friends – an array that holds Person objects. Swift’s Array type is a generic collection. It can hold any type that is created in Swift. Now, assume that we have an object of class Person, and we need its first friend name.

Compiler knows that person.friends is an an optional array that holds Person objects, so firstFriendName type is optional String. Great.

How will it look in Objective-c?

Before we go further, let me talk a little about nonnull and nullable property attributes. These are called nullability annotations and were introduced with Xcode 6.3. A __nullablepointer can have nil or NULL value, while a _nonnull one cannot. If you break these rules, the compiler will let you know.

Now, we can go back to generics. We couldn’t define the type of elements in our friendsarray. As in the Swift example, assume that we have an object of class Person, and we need its first friend’s name. Due to the lack of generics, we first need a variable assigned to the first element of the array:

Because of no generics in Objective-C, person.friends.firstObject is of type id, notPerson. id is a pointer to any object, which means it can be any object created in Objective-C. We don’t know explicitly that person.friends.firstObject is an instance of Person. We can assign person.friends.firstObject to a variable of type Person, but also it could be any other type, for example NSString.

The responsibility for using the right type lies with us. If we use a wrong type and, during runtime, a message that an object doesn’t respond is sent – then a runtime error will occur.

To get the first friend name, we need to create another variable:

This example is really simple, but it shows that Objective-C demands additional code and it’s the developers, not the compiler, that will be responsible for an object’s type tracking.

If Objective-C were jealous of something from Swift, Java or C#, it would probably be generics (just google „objective-c generics”). Hopefully, Xcode 7 and Objective-C Lightweight Generics come to the rescue:

Now we can define the type of values which are in a collection!

The compiler knows that firstFriendName is type of NSString. What happens if we assign an object from a collection to a variable of incorrect type?

We get a compiler warning. Nice.
Look how Swift imports the Objective-C Person class:

Lightweight Generics don’t apply only to NSArray. They can also be used with two other of Foundation’s collection classes – NSDictionary and NSSet.

What’s more, you can use Objective-C Lightweight Generics in your custom classes:

What happens if we use the wrong type?

The compiler will behave as before and give us a warning.

Bear in mind that now Objective-C generics in custom classes behave a little different than in NSArray, NSSet and NSDictionary. They are ignored by Swift. If we import them into Swift, they will be treated as if they were unparameterized. Fortunately this will change with Swift 3.

What is the result of introducing Objective-C lightweight generics in Xcode 7? The necessity of typecasting is reduced. Responsibility for tracking an object type is moved from developer to compiler. The code is cleaner, type safer, and less prone to error. But that’s not all – before Xcode 7 you needed to be careful when working with Objective-C frameworks in Swift. Every object from an Objective-C collection needed to be cast asAnyObject. Introducing Objective-C generics resolves this problem and results in better Swift – Objective-C interoperability.

Originally posted on netguru blog.