Swift/Obj-C interop: Prevent bridging of Foundation classes?

Viewed 150

I have an Obj-C category on NSLocale implementing these readonly properties:

@property (class, nonatomic, nonnull, readonly) NSLocale *searchLocale;
@property (nonatomic, nonnull, readonly) NSString *extendedLanguageCode;

Now when I wanna access it from Swift, I've to write (NSLocale.search as NSLocale).extendedLanguageCode. Is there a way to avoid the casting to NSLocale?

I'm aware I could write a Swift extension like this:

extension Locale {
    var extendedLanguageCode: String {
        (self as NSLocale).extendedLanguageCode
    }
}

However, that doesn't scale well. I have multiple properties and I'd need such glue code for all of them.

So I was looking for a switch to tell the compiler that for a specific class property it should not apply the bridging from NSLocale to Locale and actually return an NSLocale in Swift.

Any idea how to solve this?

2 Answers

Workaround with cheating obviously not preventing the autobridging of Foundation classes.

@interface MyLocale : NSLocale
@end

@interface NSLocale (YourCategory)
@property (class, nonatomic, nonnull, readonly) MyLocale *search;
@property (nonatomic, nonnull, readonly) NSString *extendedLanguageCode;
@end

Now in Swift you can use

_ = NSLocale.search.extendedLanguageCode

However I found a promising set of Clang attributes (look up the Customizing Swift Import section) here https://clang.llvm.org/docs/AttributeReference.html#swift-bridge.

Update
I was only able to effectively use

@property (class, nonatomic, nonnull, readonly) NSLocale* search __attribute__((swift_name("search2")));

&

@property (class, nonatomic, nonnull, readonly) NSLocale* search __attribute__((swift_private));

Essentially giving a custom Swift name to the property or making it private. Not particularly impressive.

Nope, you cannot get rid of the extension that forwards to the Objective-C implementation.

This is because Swift's Locale is a ReferenceConvertible over NSLocale, so any new methods/properties you add over NSLocale will need to be implemented on the Swift struct side too. This is the old classic "composition over inheritance" pattern.

I agree on some level on the scaling issue, however how many methods could you add over NSLocale to get into problems? :)

Related