shariebg
shariebg

Reputation: 109

Cannot find methods with parameters of Swift class in Objective-C

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

Upvotes: 2

Views: 1441

Answers (2)

Adrian
Adrian

Reputation: 16725

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)

Upvotes: 0

David Pasztor
David Pasztor

Reputation: 54716

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 {
    ...
}

Upvotes: 2

Related Questions