The Insider's Guide to Objective-C Generics
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, let us talk a little about Objective-C Generics.
Sure, WWDC 2015 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 mobile app 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 us 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 __nullable
pointer 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 friends
array. 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
, not Person
. 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 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.
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, the 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 as AnyObject
. Introducing Objective-C generics resolves this problem and results in better Swift - Objective-C interoperability.
Hey iOS developers, are you also into Swift? After its update announced on WWDC, we posted a guide to error handling - dive in and find out more!