Why SPM library with Objective-C NSURL category is not available in Swift URL type?

I asked the same question in Stackoverflow and no luck yet. So I post it here hoping my luck to change.

I created an SPM small. library with some Objective-C code. Some code is a category on NSURL class.

@interface NSURL (Additions)
@property (copy, readonly) NSDictionary<NSString *, NSString *> *queryParams;
@end

Then I import my library into a Swift project

import URLUtils

and I am able to do:

// Sigh: queryParams is available in NSURL as expected
let url = NSURL(string: "https://domain.com/path?a=123")!
let queryParams = url.queryParams

But I am NOT able to do this (It does not compile):

// Sigh I want to be able to use URL and have my category method automatically bridged. Is this possible?!
let url = URL(string: "https://domain.com/path?a=123")!
let queryParams = url.queryParams
//                    ^ error: value of type 'URL' has no member 'queryParams'

Sample code here just run the tests: swift test.

Why is this? Is this the expected behaviour for SPM packages? I have an old app with lots of Objective-C code and want to move them into a few SPM packages rather than having a huge bridging header file in the app.

NSURL and URL are not the same type. The first is a class, the second a struct. ObjC categories or Swift extensions to one do not apply to the other.

There's a runtime "magic" that ties them together, though. It is the URL conformance to ReferenceConvertible, and much probably some non-public tricks. But this does not make them the same type.

3 Likes

NSURL in ObjectiveC will be imported into as URL by default in Swift.

You can use as NSURL to bridge back and get all the category/extension on NSURL.

And in your case, if you want to use URL directly. You can add an extension for URL

extension URL {
    var queryParams: [String: String] {
        (self as NSURL).queryParams
    }
}
3 Likes

Thank you gwendal.roue and Kyle-Ye. I realized what/why is happening so I got that the solution is to create an extension like Kyle-Ye suggested.

I have updated my original repository source code and it works ok now!.