2

I have a problem with the Swift and Objective-C interoperability. In my Objective-C class the methods with parameters of my Swift class are not recognized. I have integrated the Swift class with the Bridging-Header correctly. Furthermore the Swift class inherits from NSObject and the variables and methods are declared with @objc. I have also tried @objcmembers... I can't find a solution to my problem on the internet. I am really desperate. My Swift class uses classes from other projects, which are also declared with @objc. Below is an example of my problem:

Project A: SwiftClassA

public class SwiftClassA: NSObject {

    @objc public init() {
        // do something
    }

    @objc public func aFunction() {
        // do something
    }
}

Project B: SwiftClassB

import ProjectA

public class SwiftClassB: NSObject {

    @objc public init(testA: Double, testB: Double) {
        // do something
    }

    @objc public func bFunction() {
        let classA = SwiftClassA()
        // do something
    }
}

Project C: SwiftClassC

import ProjectA
import ProjectB

public class SwiftClassC: NSObject {
@objc public var classA: SwiftClassA

    @objc public init(classA: SwiftClassA) {
        self.classA = classA
    }

    @objc public func cFunction(testA: Double, testB: Double) {
        let classB = SwiftClassB(testA: testA, testB: testB)
        // do something
    }

    @objc public func  cFunction() {
        // do something
        return
    }
}

Project C: ObjcClass

#import <ProjectA-Swift.h>
#import <ProjectC-Swift.h>

@property (nonatomic, strong) SwiftClassC *swiftClassC;

@implementation ObjcClass

- (ObjcClass *_Nonnull)init {
        SwiftClassA *swiftClassA = [[SwiftClassA alloc] init];
        _swiftClassC = [[SwiftClassC alloc] initWithClassA: swiftClassA];
        return self;
}

- (void)objcFunction { 
        [_swiftClassC cFunctionWithTestA: 1.0 testB: 1.0]; // Property ‚FunctionWithTestA' not found on object of type ’SwiftClassC *’
        [_swiftClassC cFunction];
}

@end
2
  • You don't need to put @objc in front of everything. You can just put @objcMembers in front of your class declaration, like so: @objcMembers public class SwiftClassC: NSObject { // code } Commented Sep 29, 2020 at 1:37
  • I have already tried that. Unfortunately it did not solve my problem. Commented Sep 29, 2020 at 7:06

2 Answers 2

2

You need to mark the classes as @objc too, it isn't enough to mark their methods as @objc.

@objc public class SwiftClassA: NSObject {

    @objc public init() {
        // do something
    }

    @objc public func aFunction() {
        // do something
    }
}

@objc public class SwiftClassB: NSObject {
    ...
}


@objc public class SwiftClassC: NSObject {
    ...
}
Sign up to request clarification or add additional context in comments.

Comments

0

Without actually seeing the project, it's tough to diagnose, however I would recommend not putting @objc in front of everything within your Swift classes. Instead, put @objcMembers in front of your Swift class declaration.

Your declarations would look like this:

@objcMembers
public class SwiftClassA: NSObject {

    public override init() {
        // do something
    }

    public func aFunction() {
        // do something
    }
}

@objcMembers
public class SwiftClassB: NSObject {

    public init(testA: Double, testB: Double) {
        // do something
    }

    public func bFunction() {
        let classA = SwiftClassA()
        // do something
    }
}

@objcMembers
public class SwiftClassC: NSObject {
    public var classA: SwiftClassA

    public init(classA: SwiftClassA) {
        self.classA = classA
    }

    public func cFunction(testA: Double,
                          testB: Double) {
        let classB = SwiftClassB(testA: testA,
                                 testB: testB)
        // do something
    }

    public func cFunction() {
        // do something
        return
    }
}

The other thing to be aware of is if your project doesn't compile, you won't get the swift header file that Objective-C reads from:

#import <ProjectA-Swift.h>
#import <ProjectC-Swift.h>

In the Objective-C code I've converted, I occasionally run into issues with the import declaration where it wants @import "ProjectA-Swift.h" instead of the one you used, so you could try playing around with that, as well.

Lastly, might want to open up your Objective-C header and click the little 4 square thingie at the upper left corner and click "Swift 5 generated interface", which, when clicked, will give you something that looks very similar to a protocol declaration...there won't be methods and vars, but it'll show you what the compiler is expecting from a method signature standpoint.

If you encounter a situation where Objective-C wants a specific signature for a method, you can use an alias in front of the method that doesn't match. An alias would look something like this:

@objc(myMethod:parameter1:parameter2)

2 Comments

Many thanks for your detailed answer. Nevertheless it could not solve my problem. The projects compile fine and unfortunately, I can't use @import "ProjectA-Swift.h" because my project uses C++ modules. I get the error message: Use of '@import' when C++ modules are disabled, consider using -fmodules and -fcxx-modules. The "Swift 5 generated interface" also didn't help me. The problem has something to do with SwiftClassC und ObjcClass. I can access the SwiftClassC functions without parameters, but not those with parameters. Alias also didn't help...
I can't see your actual code, but you will want to check to make sure the properties and methods you're converting map 1:1 to Swift. Some properties won't be recognized by ObjC (ex Number). In those circumstances, you can define a property w/ a setter/getter to be used by ObjC callers which updates to Swift only property in your code. Based on what you describe, the problem sounds like there's either a bridging header issue or there's something in your Swift class that's preventing it from creating the -Swift file

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.