Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a generic Swift class in Objective-C

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?

like image 330
Senseful Avatar asked Sep 04 '15 21:09

Senseful


People also ask

Can we use Swift class in Objective-C?

You can work with types declared in Swift from within the Objective-C code in your project by importing an Xcode-generated header file. This file is an Objective-C header that declares the Swift interfaces in your target, and you can think of it as an umbrella header for your Swift code.

Does Objective-C support Generics?

Objective-C supports lightweight Generics since 2015, with the Xcode 7.

How do you inherit a Swift class in Objective-C?

Swift classes that are inherited from OBJC classes are bridged automatically. That means any class inherited from, for example, UIViewController is automatically seen in the OBJC runtime. If you're creating a class that doesn't inherit from anything, then make it an NSObject subclass, as you would in OBJC.


2 Answers

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
  • ...
like image 168
newacct Avatar answered Oct 10 '22 19:10

newacct


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];
}
like image 34
medvedNick Avatar answered Oct 10 '22 18:10

medvedNick