ObjC categories not recognised from a different target

30 Views Asked by At

I have an iOS SwiftUI project with the following hierarchy:

Module hierarchy:

AppTarget -> depends on Experience
Experience -> depends on Lifecycle
Lifecycle

Content of each module:
Lifecycle 
  -- struct conforming App protocol (entry point)
  -- AppDelegate, SceneDelegate etc.
Experience
  -- URLHandler (and other supporting classes to handle launch parameters (if app is launched by tapping an associated file, quick action etc..) and update the UI.

I have a struct conforming to App protocol in the Lifecycle library. It defines the onOpenURL(perform:) method to handle all URL based launches (widgets, files, deep links, universal links etc.).

// In Lifecycle library

WindowGroup {
    ContentView()
        .onOpenURL(perform: { (url: URL) in
            // Handle URL with which the app is launched.
        })
}

In the above method, I need to invoke the URL handler method in Experience library. Note that the Experience library is above Lifecycle in the hierarchy (as mentioned above), so I cannot simply directly invoke it.

I'm thinking of using ObjC categories to achieve this. ObjC category is a way to add methods to an existing class. At runtime, all methods in the category would be under one single class, though they are defined in two files in different modules.

In Lifecycle library, I define the class as below:

// In header file,
@interface  URLHandler : NSObject

// No methods defined here.
// Experience extends this using the concept of
// ObjC category and defines a handler method
// to handle all URL handler launches.

@end

// In .mm file, 
@implementation URLHandler

// Empty

@end

And in the Experience library, I'm extending them as shown below:

// In header file, extend the base class in Lifecycle library
// by creating a category.
@interface URLHandler (Experience)

+ (void) handleURL:(NSURL *) url;

@end

// In .mm file,
@implementation URLHandler (Experience)

+ (void) handleURL:(NSURL *) url {
    Log([NSString stringWithFormat:@"(ObjC++) url = %@", [url absoluteString]]);

    // Update the UI after 'understanding' the URL.
}

@end

And, in the onOpenURL(perform:) method, invoke handleURL: method,

WindowGroup {
    ContentView()
        .onOpenURL(perform: { (url: URL) in
            URLHandler.handleURL(url)
        })
}

As per my understanding, everything seems fine... but I get a compilation error

Type 'URLHandler' has no member 'handleURL'

Isn't category a runtime feature? At runtime, handleURL: method should be part of URLHandler. But how do I get past this error at compile time?

Is this not possible using ObjC? If yes, is there any other way?

Edit1: I am using the latest Cpp-Swift interop introduced in WWDC 2023, which uses a module map to expose C++ and ObjC types to Swift. I believe I've done that correctly since the error is not undefined symbol: URLHandler but a method not being available in the class, which I implemented in the category.

0

There are 0 best solutions below