Search code examples
swiftobjective-cswift-package-managerobjective-c-category

SPM library with Objective-C NSURL category not imported into Swift URL?


I have created a SPM package with a bunch of old Objective-C code (I want to convert some old code "Objective-C code with a big bridging header" into "Objective-C in some SPM packages") For most of the cases it works OK except for Objective-C categories like:

@import Foundation;

@interface NSURL (Additions)

@property (copy, readonly) NSDictionary<NSString *, NSString *> *queryParams;

@end

Problem: Property queryParams is NOT available in Swift on URL types but only on NSURL types. This looks odd to me because when declaring the same category in an App and using the bridging header file, then queryParams is also usable from URL type too.

Tests/URLUtilsTests/URLUtilsTestsSwift.swift:18:31: error: value of type 'URL' has no member 'queryParams'
        let queryParams = url.queryParams
                          ~~~ ^~~~~~~~~~~
error: fatalError

Question: What do I need to have queryParams in both NSURL and URL while using SPM?

I have created a repo in GitHub with reproducing problem

This is a screenshot of my entire package:

enter image description here


Solution

  • I asked the same question in Swift forums and I got the reason why this is not working.

    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 5, and much probably some non-public tricks. But this does not make them the same type.

    So the only solution is to have a special target for swift code.

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

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