Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access an internal Swift class in Objective-C within the same framework?

Working on a mixed framework. imported inside the Obj-C file but the internal classes are not visible, only the public ones.

The documentation clearly states the internal clasees should be available between Swift and Obj-C:

Importing Swift into Objective-C
To import a set of Swift files in the same framework target as your Objective-C code, you don’t need to import anything into the umbrella header for the framework. Instead, import the Xcode-generated header file for your Swift code into any Objective-C .m file you want to use your Swift code from. Because the generated header for a framework target is part of the framework’s public interface, only declarations marked with the public modifier appear in the generated header for a framework target. You can still use Swift methods and properties that are marked with the internal modifier from within the Objective-C part of your framework, as long they are declared within a class that inherits from an Objective-C class. For more information on access-level modifiers, see Access Control in The Swift Programming Language (Swift 2).

Code Sample (Create a new project with a framework)

// SwiftObject.swift

public class SwiftObject: NSObject {
    public class func doSomething() {}
}

internal class YetAnotherSwiftObject: NSObject {
    internal class func doSomething() {}
}

// SomeObject.m file

@implementation SomeObject

- (void)someMethod {
    [SwiftObject doSomething];
}

- (void)someOtherMethod {
    [YetAnotherSwiftObject doSomething]; // Use of undeclared identifier
}

@end
like image 988
Yariv Nissim Avatar asked Sep 21 '15 16:09

Yariv Nissim


People also ask

How do I access Swift in Objective-C?

Import Swift code into Objective-C within the same framework: Under Build Settings, in Packaging, make sure the Defines Module setting for that framework target is set to Yes. Import the Swift code from that framework target into any Objective-C .

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

Unfortunately, it's not possible to subclass a Swift class in Objective-C. Straight from the docs: You cannot subclass a Swift class in Objective-C. See Apple's guide on interoperability for more details on what you can and cannot access with Objective-C.

Can I use Swift package in Objective-C?

The Swift Package Manager allows developers to build reusable components made up of Swift, Objective-C, Objective-C++, C, or C++ code that other developers can use in their own projects.

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

Unfortunately, that is the case. You cannot subclass a Swift class (even if it is a subclass of NSObject and available to the Objective-C runtime) because of deliberate limitations baked into Obj-C to block subclassing Swift classes in Obj-C code.


1 Answers

As indicated in the docs, declarations marked with internal modifier don't appear in the generated header, so the compiler does not know about them and thus complaints. Of course, you could send messages using performSelector approach, but that's not convenient and bug-prone. We just need to help the compiler know that those declarations are there.

First, we need to use @objc attribute variant that allows you to specify name for your symbol in Objective-C:

// SwiftObject.swift

@objc(SWIFTYetAnotherSwiftObject)
internal class YetAnotherSwiftObject: NSObject {
    internal class func doSomething() {}
}

And then you just need to create @interface declaration with the methods you want to use in your code - so the compiler will be happy, and also apply SWIFT_CLASS macro with the symbol name you've specified earlier - so the linker would pick the actual implementation:

// SomeObject.m file

SWIFT_CLASS("SWIFTYetAnotherSwiftObject")
@interface YetAnotherSwiftObject : NSObject

+ (void)doSomething;

@end


@implementation SomeObject

- (void)someOtherMethod {
    [YetAnotherSwiftObject doSomething]; // Should work now !!!
}

@end
  • I've used the interface declaration in .m file just for clarity, the better option would be to combine such declarations in .h file, and include it.
  • By declaring methods in that interface we're making a promise to compiler, and it won't complain if you'll put there a method that does not exist (or with wrong signature, etc.) Obviously, you'll crash in runtime in that case - so be cautious.
like image 163
Vladimir Kofman Avatar answered Oct 07 '22 14:10

Vladimir Kofman