31
votes

Let's say I define a generic class in Swift, similar to the following:

class MyArray<T> {
    func addObject(object: T) {
        // do something... hopefully
    }
}

(I know there is a slightly better implementation of array, this is merely an example.)

In Swift I can now use this class very easily:

let a = MyArray<String>()
a.addObject("abc")

With Xcode 7, we now have generics in Objective-C, so I would assume that I could use this class in Objective-C:

MyArray<NSString*> *a = [[MyArray<NSString*> alloc] init];
[a addObject:@"abc"];

However, MyArray is never added to my Project-Swift.h file. Even if I change it to inherit from NSObject, it still doesn't appear in my Swift.h file.

Is there any way to create a generic Swift class and then use it in Objective-C?


Update: If I try to inherit from NSObject and annotate with @objc:

@objc(MyArray)
class MyArray<T>: NSObject {
    func addObject(object: T) {
        // do something... hopefully
    }
}

I get the following compiler error:

Generic subclasses of '@objc' classes cannot have an explicit '@objc' attribute because they are not directly visible from Objective-C.

Does this mean there is no way to use a generic Swift class in Objective-C?

How does one indirectly reference the class?

2
Did you annotate your class with an @objc?Mr Beardsley
@MrBeardsley I just tried it and it gave an interesting compiler error (see above).Senseful

2 Answers

28
votes

Swift generic types cannot be used in Objective-C.

https://developer.apple.com/library/content/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html#//apple_ref/doc/uid/TP40014216-CH10-ID136

This excludes Swift-only features such as those listed here:

  • Generics
  • ...
7
votes

There is a workaround for some situations, when you need to import Swift generic class into Objective-C.

Let's say you have Swift REST service, which uses Generics. I'm using Moya framework and that's how my service looks like:

 class AuthService: BaseService<AuthAPI> {
    func register(email: String)  {
       // ... 
    }
 }

It's inherited from base service using generics, so I can not use it directly in my Objective-C code.

So here is a workaround:

Lets create AuthServiceProtocol:

@objc protocol AuthServiceProtocol {
    func register(email: String)
}

Then let's create a factory for service (or a singleton method, no difference):

@objc class Services: NSObject {
    static let authService: AuthServiceProtocol = AuthService()
}

Then I'm able to call my generic Swift auth service from Objective-C code:

- (void)someObjcMethod {
    [Services.authService registerWithEmail:self.email];
}