Extend Obj-c Generics in Swift

Derrick Ho
3 min readJul 2, 2017

Objective-c has light weight generics that allows you to write a generic class. Suppose we had a class dedicated to processing data into a different type.

NS_ASSUME_NONNULL_BEGIN@interface NSDataProcessor <__covariant T: id> : NSObject
- (T _Nullable)processData:(NSData *)data;
@end
NS_ASSUME_NONNULL_END

A generic class like this allows us to specify that we want the data processing to return a type of NSString rather than a type of id. Xcode will help us ensure the type validity.

However, there is a bit of an elephant in the room. How would swift use this?

Swift does not automatically bridge NSString into String like a non-generic function would. I could cast it to type string with as? String that defeats the purpose of generics, no?

The solution then is to make an extension to NSDataProcessor in swift. But you’d get into some trouble with the compiler. However there is a workaround. When the swift extension of NSDataProcessor exists in the same module as the defining class, the compiler will not allow any extension at all! But if they are in different modules its less strict.

Suppose the original objective-c implementation exists in a framework called Processor.framework. You could create another framework that depends on it called Processor_extensions.framework and add the extension in there like so:

It compiles!

it is available!

However, there are some limitations:

  • all extensions regardless of the generic type will be picked up by autocompletion. However, the compiler will only let you use the one that matches the generic’s type
  • You can’t use where T: NSString which would make the methods available to NSString and all its subclasses.
  • You can’t make any of the methods generic or access the generic type of the Objective-c generic class.

Ok, so why do we care if NSString doesn’t automatically bridge to String?

If instead we chose NSArray <NSString *>* as the generic type, although objective-c would interpret it correctly, swift would only see it as NSArray. It just isn’t swifty if it isn’t Array<String> !

Thats an exclamation mark not an Implicitly Unwrapped Optional by the way.

Anyways, back on topic this image should suffice:

And thats my roundabout way for doing what as? Array<Int> would do. Isn’t programming awesome?

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response