How do you declare a custom NSAttributedStringKey in Objective-C for Swift use?

Hi,

Swift 4 and the macOS 10.13 SDK added a new NSAttributedStringKey type for the keys that NSAttributedStrings use. The keys are then defined in an extension of NSAttributedStringKey, essentially like this in AppKit:

// AppKit/NSAttributedString.h (Objective-C)
extern NSAttributedStringKey NSFontAttributeName;

// Generated Swift Interface
extension NSAttributedStringKey {
    public static let font: NSAttributedStringKey
}

How do I get my own custom NSAttributedStringKeys to be imported this way? When I do it like AppKit, it doesn’t seem to work:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName;

// Generated Swift Interface
static let ODRolloverTokenAttributeName: NSAttributedStringKey

That is obviously not the same. I tried using the NS_SWIFT_NAME macro, but that results in the symbol disappearing in Swift completely:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(NSAttributedStringKey.rolloverToken);

I also tried to use the swift_name attribute that is used by the NS_SWIFT_NAME macro and that is even mentioned in SE-0044 for exactly this purpose, but the symbol still disappears:

extern const NSAttributedStringKey ODRolloverTokenAttributeName __attribute__((swift_name("NSAttributedStringKey.rolloverToken")));

What works is to manually define it in an extension like this, but that’s no fun:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_REFINED_FOR_SWIFT;

extension NSAttributedStringKey {
    static let rolloverToken = NSAttributedStringKey(__ODRolloverTokenAttributeName.rawValue)
}

Is there no way to import this automatically? Was this functionality removed before release even though it was mentioned in SE-0044?

Cheers,

Marco

Hi, Marco. The limitation here is that you can’t use swift_name (or NS_SWIFT_NAME) to add members to someone else’s type (more precisely, a type not declared in your module’s headers). You’re not the first to be dissatisfied with this restriction, though, particularly since as you point out you can just add a Swift-side extension to do the same thing. Within Apple, rdar://problem/31877728 <rdar://problem/31877728> tracks making the feature more general.

Similarly, the automatic import-as-member feature for NS_EXTENSIBLE_STRING_ENUMs is also only enabled for constants in the same module as the type. I’m not sure we want to rock the boat on that one.

Jordan

···

On Sep 27, 2017, at 07:07, Marco Masser via swift-users <swift-users@swift.org> wrote:

Hi,

Swift 4 and the macOS 10.13 SDK added a new NSAttributedStringKey type for the keys that NSAttributedStrings use. The keys are then defined in an extension of NSAttributedStringKey, essentially like this in AppKit:

// AppKit/NSAttributedString.h (Objective-C)
extern NSAttributedStringKey NSFontAttributeName;

// Generated Swift Interface
extension NSAttributedStringKey {
    public static let font: NSAttributedStringKey
}

How do I get my own custom NSAttributedStringKeys to be imported this way? When I do it like AppKit, it doesn’t seem to work:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName;

// Generated Swift Interface
static let ODRolloverTokenAttributeName: NSAttributedStringKey

That is obviously not the same. I tried using the NS_SWIFT_NAME macro, but that results in the symbol disappearing in Swift completely:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(NSAttributedStringKey.rolloverToken);

I also tried to use the swift_name attribute that is used by the NS_SWIFT_NAME macro and that is even mentioned in SE-0044 for exactly this purpose, but the symbol still disappears:
swift-evolution/0044-import-as-member.md at master · apple/swift-evolution · GitHub

extern const NSAttributedStringKey ODRolloverTokenAttributeName __attribute__((swift_name("NSAttributedStringKey.rolloverToken")));

What works is to manually define it in an extension like this, but that’s no fun:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_REFINED_FOR_SWIFT;

extension NSAttributedStringKey {
    static let rolloverToken = NSAttributedStringKey(__ODRolloverTokenAttributeName.rawValue)
}

Is there no way to import this automatically? Was this functionality removed before release even though it was mentioned in SE-0044?

Cheers,

Marco
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Could it be that this is (just) a problem of the generated interface _view_ ? With

    extern NSAttributedStringKey ODRolloverTokenAttributeName;

in an Objective-C header the "Generated Interface" is displayed as

   public static let ODRolloverTokenAttributeName: NSAttributedStringKey

as you noticed, but I can use it from Swift as

   let key = NSAttributedStringKey.ODRolloverTokenAttributeName

so it is actually a property of NSAttributedStringKey, not a global variable. And with

   extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(rolloverToken);

in the Objective-C header I can use it from Swift as

   let key = NSAttributedStringKey.rolloverToken

So – unless I am misunderstanding something – the ODRolloverTokenAttributeName defined in the Objective-C header file is actually imported to Swift as an extension to NSAttributedStringKey, even if the generated interface view in Xcode displays it as a global variable.

Regards, Martin

···

Am 27.09.2017 um 16:07 schrieb Marco Masser via swift-users <swift-users@swift.org>:

Hi,

Swift 4 and the macOS 10.13 SDK added a new NSAttributedStringKey type for the keys that NSAttributedStrings use. The keys are then defined in an extension of NSAttributedStringKey, essentially like this in AppKit:

// AppKit/NSAttributedString.h (Objective-C)
extern NSAttributedStringKey NSFontAttributeName;

// Generated Swift Interface
extension NSAttributedStringKey {
    public static let font: NSAttributedStringKey
}

How do I get my own custom NSAttributedStringKeys to be imported this way? When I do it like AppKit, it doesn’t seem to work:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName;

// Generated Swift Interface
static let ODRolloverTokenAttributeName: NSAttributedStringKey

That is obviously not the same. I tried using the NS_SWIFT_NAME macro, but that results in the symbol disappearing in Swift completely:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(NSAttributedStringKey.rolloverToken);

I also tried to use the swift_name attribute that is used by the NS_SWIFT_NAME macro and that is even mentioned in SE-0044 for exactly this purpose, but the symbol still disappears:
swift-evolution/0044-import-as-member.md at master · apple/swift-evolution · GitHub

extern const NSAttributedStringKey ODRolloverTokenAttributeName __attribute__((swift_name("NSAttributedStringKey.rolloverToken")));

What works is to manually define it in an extension like this, but that’s no fun:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_REFINED_FOR_SWIFT;

extension NSAttributedStringKey {
    static let rolloverToken = NSAttributedStringKey(__ODRolloverTokenAttributeName.rawValue)
}

Is there no way to import this automatically? Was this functionality removed before release even though it was mentioned in SE-0044?

Cheers,

Marco
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Oh, whoops! Good catch, Martin. I guess I was working from outdated information here. The Radar I mentioned is something else; this one is <rdar://problem/28208090> Generated interface for import-as-member doesn't include context.

Jordan

···

On Sep 27, 2017, at 11:45, Martin R via swift-users <swift-users@swift.org> wrote:

Could it be that this is (just) a problem of the generated interface _view_ ? With

   extern NSAttributedStringKey ODRolloverTokenAttributeName;

in an Objective-C header the "Generated Interface" is displayed as

  public static let ODRolloverTokenAttributeName: NSAttributedStringKey

as you noticed, but I can use it from Swift as

  let key = NSAttributedStringKey.ODRolloverTokenAttributeName

so it is actually a property of NSAttributedStringKey, not a global variable. And with

  extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(rolloverToken);

in the Objective-C header I can use it from Swift as

  let key = NSAttributedStringKey.rolloverToken

So – unless I am misunderstanding something – the ODRolloverTokenAttributeName defined in the Objective-C header file is actually imported to Swift as an extension to NSAttributedStringKey, even if the generated interface view in Xcode displays it as a global variable.

Regards, Martin

Am 27.09.2017 um 16:07 schrieb Marco Masser via swift-users <swift-users@swift.org>:

Hi,

Swift 4 and the macOS 10.13 SDK added a new NSAttributedStringKey type for the keys that NSAttributedStrings use. The keys are then defined in an extension of NSAttributedStringKey, essentially like this in AppKit:

// AppKit/NSAttributedString.h (Objective-C)
extern NSAttributedStringKey NSFontAttributeName;

// Generated Swift Interface
extension NSAttributedStringKey {
   public static let font: NSAttributedStringKey
}

How do I get my own custom NSAttributedStringKeys to be imported this way? When I do it like AppKit, it doesn’t seem to work:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName;

// Generated Swift Interface
static let ODRolloverTokenAttributeName: NSAttributedStringKey

That is obviously not the same. I tried using the NS_SWIFT_NAME macro, but that results in the symbol disappearing in Swift completely:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(NSAttributedStringKey.rolloverToken);

I also tried to use the swift_name attribute that is used by the NS_SWIFT_NAME macro and that is even mentioned in SE-0044 for exactly this purpose, but the symbol still disappears:
swift-evolution/0044-import-as-member.md at master · apple/swift-evolution · GitHub

extern const NSAttributedStringKey ODRolloverTokenAttributeName __attribute__((swift_name("NSAttributedStringKey.rolloverToken")));

What works is to manually define it in an extension like this, but that’s no fun:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_REFINED_FOR_SWIFT;

extension NSAttributedStringKey {
   static let rolloverToken = NSAttributedStringKey(__ODRolloverTokenAttributeName.rawValue)
}

Is there no way to import this automatically? Was this functionality removed before release even though it was mentioned in SE-0044?

Cheers,

Marco
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Oh, nice, thank you Martin! It absolutely makes sense that the type does not have to be specified in the NS_SWIFT_NAME macro since that should be clear from the declaration itself. I didn’t think about that. Still, it seems like a little bit more magic than usual that the global scope Objective-C constant moves to the Swift type without the user explicitly stating that. But again, it does make sense.

Also, while trying out different ways to spell this out, it didn’t exactly help that the generated interface doesn’t include the context. Glad to see that this issue is already tracked by Apple. Thanks for your comments on that, Jordan.

Cheers,

Marco

···

On 2017-09-27, at 21:38, Jordan Rose <jordan_rose@apple.com> wrote:

Oh, whoops! Good catch, Martin. I guess I was working from outdated information here. The Radar I mentioned is something else; this one is <rdar://problem/28208090> Generated interface for import-as-member doesn't include context.

Jordan

On Sep 27, 2017, at 11:45, Martin R via swift-users <swift-users@swift.org> wrote:

Could it be that this is (just) a problem of the generated interface _view_ ? With

  extern NSAttributedStringKey ODRolloverTokenAttributeName;

in an Objective-C header the "Generated Interface" is displayed as

public static let ODRolloverTokenAttributeName: NSAttributedStringKey

as you noticed, but I can use it from Swift as

let key = NSAttributedStringKey.ODRolloverTokenAttributeName

so it is actually a property of NSAttributedStringKey, not a global variable. And with

extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(rolloverToken);

in the Objective-C header I can use it from Swift as

let key = NSAttributedStringKey.rolloverToken

So – unless I am misunderstanding something – the ODRolloverTokenAttributeName defined in the Objective-C header file is actually imported to Swift as an extension to NSAttributedStringKey, even if the generated interface view in Xcode displays it as a global variable.

Regards, Martin

Am 27.09.2017 um 16:07 schrieb Marco Masser via swift-users <swift-users@swift.org>:

Hi,

Swift 4 and the macOS 10.13 SDK added a new NSAttributedStringKey type for the keys that NSAttributedStrings use. The keys are then defined in an extension of NSAttributedStringKey, essentially like this in AppKit:

// AppKit/NSAttributedString.h (Objective-C)
extern NSAttributedStringKey NSFontAttributeName;

// Generated Swift Interface
extension NSAttributedStringKey {
  public static let font: NSAttributedStringKey
}

How do I get my own custom NSAttributedStringKeys to be imported this way? When I do it like AppKit, it doesn’t seem to work:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName;

// Generated Swift Interface
static let ODRolloverTokenAttributeName: NSAttributedStringKey

That is obviously not the same. I tried using the NS_SWIFT_NAME macro, but that results in the symbol disappearing in Swift completely:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_SWIFT_NAME(NSAttributedStringKey.rolloverToken);

I also tried to use the swift_name attribute that is used by the NS_SWIFT_NAME macro and that is even mentioned in SE-0044 for exactly this purpose, but the symbol still disappears:
swift-evolution/0044-import-as-member.md at master · apple/swift-evolution · GitHub

extern const NSAttributedStringKey ODRolloverTokenAttributeName __attribute__((swift_name("NSAttributedStringKey.rolloverToken")));

What works is to manually define it in an extension like this, but that’s no fun:

// My Objective-C header
extern NSAttributedStringKey ODRolloverTokenAttributeName NS_REFINED_FOR_SWIFT;

extension NSAttributedStringKey {
  static let rolloverToken = NSAttributedStringKey(__ODRolloverTokenAttributeName.rawValue)
}

Is there no way to import this automatically? Was this functionality removed before release even though it was mentioned in SE-0044?

Cheers,

Marco
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users