Ghostboard pixel

Objective-C: Lightweight Generics

Objective-C:  Lightweight Generics

Since Xcode 7 there are so-called “Lightweight” Generics in Objective-C. The biggest benefit of this feature is a better interoperability between Objective-C and Swift.

The Basics

Let’s start with an example. Before the introduction of generics, you declared a mutable array in Objective-C as follows:

NSMutableArray *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:@"Test1"];
[stringArray addObject:@"Test2"];

Now you have the possibility to declare a type for the array items:

NSMutableArray<NSString*> *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:@"Test1"];
[stringArray addObject:@"Test2"];

But what has changed? There is now change in the compiler output, but if you try to add an object of a different type there will be a warning:

NSMutableArray<NSString*> *stringArray = [[NSMutableArray alloc] init];
[stringArray addObject:@"Test1"];
[stringArray addObject:@"Test2"];

//WARNING: Incompatible pointer types sending 'NSNumber*' 
//to parameter of type 'NSString*'
[stringArray addObject:[NSNumber numberWithInt:5]];

There will be no runtime error, because the Objective-C runtime did not change at all!

Of course you can declare a class on your own that uses generic types.  Take a look at the following header file:

@interface GenericsTest<ObjectType> : NSObject

- (ObjectType)anObject:(ObjectType)obj;

@end

After the class’ name, you declare a generic type. Then you can use this type for parameter and return types.

But what do you do in the implementation file? Just use id ! So the .m looks as follows:

@implementation GenericsTest

- (ObjectType)anObject:(id)obj {

    //...

}

@end

Interoperability between Objective-C and Swift

Imagine you declare a function like

- (void) doSomethingImportant:(NSArray<UIView*>*) views;

and you try to call this function in Swift, then you have to use an array of UIViews! The same holds true with return values, so you don’t need to cast as much as you were used to.

Unfortunately, there is the following paragraph in Apple’s documentation:

   Aside from than these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.

So the use of your own classes with generic types has only benefits within Objective-C code.

Conclusion

Lightweight Generics are very useful for the interoperability between Objective-C and Swift – at least  regarding collection classes. Nevertheless this is a huge benefit, because you save a lot of casts in your code, since all of Apple’s frameworks are written in Objective-C.