1

I have a swift class containing a lot of methods. I've split it into multiple classes using the extension keyword.

Taking an example,

@objc
class SwiftModule : NSObject {
    
    @objc
    static func Method1 (_ pArg:UnsafeMutablePointer<NSString>) -> Void {                
        // Does something
    }

    @objc
    static func Method2 (_ pArg:UnsafeMutablePointer<NSString>) -> Void {   
        // Does something             
    }
}

@objc
extension SwiftModule {

    @objc
    static func Method3 (_ pArg:UnsafeMutablePointer<NSString>) -> Void {           
        // Does something
    }
}

Now, I have to invoke this method from C++ using the ObjC++ wrapper. I have the following in a .mm file,

// Include the generated swift interface header to invoke swift methods from C++
#include    "GeneratedSwiftInterfaceHeader.hpp"

bool CppModule::InvokeMethod1 () {

    NSString *  string;

    [SwiftModule Method1:&string];

    if ([string length] == 0)
        return false;

    // Do something with string

    return true;
}

bool CppModule::InvokeMethod2 () {

    NSString *  string;

    [SwiftModule Method2:&string];

    if ([string length] == 0)
        return false;

    // Do something with string

    return true;
}

bool CppModule::InvokeMethod3 () {

    NSString *  string;

    [SwiftModule Method3:&string];

    if ([string length] == 0)
        return false;

    // Do something with string

    return true;
}

I'm able to invoke Method1 and Method2. But Method3 failed with the following error

ibc++abi: terminating with uncaught exception of type NSException
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[SwiftModule Method3:]: unrecognized selector sent to class 0x107343398'
terminating with uncaught exception of type NSException
(lldb) 

This means that Method3 is not recognised as part of SwiftModule class, right? Why? Where did I go wrong?

I have seen a few posts (this and this) which showcase a similar problem, but it still doesn't work.

I'm using swift 5.0 and Xcode 13.4.

NightFuryLxD
  • 847
  • 5
  • 15
  • The code you shared compiles and works just fine on my end. Could you [edit] the question and include *exact text* of the error. It might be that unrecognised selector has nothing to do with the Swift methods being called, but rather with what is called from inside of the said methods – The Dreams Wind Sep 05 '22 at 10:55
  • @TheDreamsWind, I copy pasted the exact error. Previously, I had only censored the file and method names. – NightFuryLxD Sep 05 '22 at 12:46
  • Sounds about right. What is this `GeneratedSwiftInterfaceHeader.hpp`? Did you write it manually? If so, could you also include it in the question? – The Dreams Wind Sep 05 '22 at 13:23
  • @TheDreamsWind, That's the header file generated by Xcode? Methods marked with the attribute '@objc' are exposed to the ObjC (and ObjC++) layers through the generated interface header. We have to include it manually (which is unlike a Bridge header, as it gets imported automatically in every swift file) and Xcode will generate it during the build time. The generated interface header has a particular format (ends with -Swift.h etc), but I changed it in the target's swift compiler settings. – NightFuryLxD Sep 06 '22 at 02:43
  • Is the target a framework or a static library? – The Dreams Wind Sep 06 '22 at 07:08
  • Originally I had many targets (static libs) and linked them all to build an app. But when you said it was working fine for you, I created an independent Xcode project (CommandLine tool), created a swift class and extended it....then tried calling the extended class's method from ObjC++ layer...It worked. No crashes. But in the big project, its failing, even though the syntax and everything else seems to be the same. Any idea what could be causing this problem? – NightFuryLxD Sep 06 '22 at 11:52
  • 1
    When importing static libraries, object files don't include Objective-C categories, it's a [known issue](https://developer.apple.com/library/archive/qa/qa1490/_index.html) which you can fix by adding `-ObjC` linker flag to the executable target (the target which has the libraries linked, not the libraries targets themselves) – The Dreams Wind Sep 06 '22 at 12:11
  • Adding -ObjC linker flag worked. Thanks. Put this as an answer? I'll accept it. – NightFuryLxD Sep 08 '22 at 05:01

1 Answers1

1

When discussing the problem in details in the comments section, it turned out that the Objective-C interfaces generated were part of a static library which the final project is linked against.

There is a known issue with Objective-C categories inside of static libraries, where the categories methods implementation are not "glued" to their symbolic names by linker. In order to get it round you pass -ObjC flag to the linker in the application (not library) target build settings. It will make the linker to load all symbols of static libraries found in both Objective-C classes and categories: enter image description here

The Dreams Wind
  • 8,416
  • 2
  • 19
  • 49