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

**URL:** <https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727>\
**Category:** Using Swift\
**Created:** [September 27, 2017, 2:07pm UTC](https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727 "2017-09-27T14:07:34Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![marco.masser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/marco.masser/32/6010_2.png) [@marco.masser](https://forums.swift.org/u/marco.masser)\
**Post date:** [September 27, 2017, 2:07pm UTC](https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727/1 "2017-09-27T14:07:34Z")

</div>

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 {  
&nbsp;&nbsp;&nbsp;&nbsp;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:

> <https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift_name-attribute>

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 {  
&nbsp;&nbsp;&nbsp;&nbsp;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

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [September 27, 2017, 4:21pm UTC](https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727/2 "2017-09-27T16:21:54Z")

</div>

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 {  
> > &nbsp;&nbsp;&nbsp;&nbsp;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:  
> > [https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift\_name-attribute](https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift_name-attribute)
> > 
> > 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 {  
> > &nbsp;&nbsp;&nbsp;&nbsp;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](https://lists.swift.org/mailman/listinfo/swift-users)

---

<div class="post-metadata">

**Author:** ![Martin](https://avatars.discourse-cdn.com/v4/letter/m/73ab20/32.png) [@Martin](https://forums.swift.org/u/Martin)\
**Post date:** [September 27, 2017, 6:45pm UTC](https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727/3 "2017-09-27T18:45:14Z")

</div>

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

&nbsp;&nbsp;&nbsp;&nbsp;extern NSAttributedStringKey ODRolloverTokenAttributeName;

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

&nbsp;&nbsp;&nbsp;public static let ODRolloverTokenAttributeName: NSAttributedStringKey

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

&nbsp;&nbsp;&nbsp;let key = NSAttributedStringKey.ODRolloverTokenAttributeName

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

&nbsp;&nbsp;&nbsp;extern NSAttributedStringKey ODRolloverTokenAttributeName NS\_SWIFT\_NAME(rolloverToken);

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

&nbsp;&nbsp;&nbsp;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 {  
> > &nbsp;&nbsp;&nbsp;&nbsp;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:  
> > [https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift\_name-attribute](https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift_name-attribute)
> > 
> > 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 {  
> > &nbsp;&nbsp;&nbsp;&nbsp;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](https://lists.swift.org/mailman/listinfo/swift-users)

---

<div class="post-metadata">

**Author:** ![jrose](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jrose/32/408_2.png) [@jrose](https://forums.swift.org/u/jrose)\
**Post date:** [September 27, 2017, 7:38pm UTC](https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727/4 "2017-09-27T19:38:45Z")

</div>

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
> > 
> > &nbsp;&nbsp;&nbsp;extern NSAttributedStringKey ODRolloverTokenAttributeName;
> > 
> > in an Objective-C header the "Generated Interface" is displayed as
> > 
> > &nbsp;&nbsp;public static let ODRolloverTokenAttributeName: NSAttributedStringKey
> > 
> > as you noticed, but I can use it from Swift as
> > 
> > &nbsp;&nbsp;let key = NSAttributedStringKey.ODRolloverTokenAttributeName
> > 
> > so it is actually a property of NSAttributedStringKey, not a global variable. And with
> > 
> > &nbsp;&nbsp;extern NSAttributedStringKey ODRolloverTokenAttributeName NS\_SWIFT\_NAME(rolloverToken);
> > 
> > in the Objective-C header I can use it from Swift as
> > 
> > &nbsp;&nbsp;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 {  
> > > &nbsp;&nbsp;&nbsp;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:  
> > > [https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift\_name-attribute](https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift_name-attribute)
> > > 
> > > 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 {  
> > > &nbsp;&nbsp;&nbsp;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](https://lists.swift.org/mailman/listinfo/swift-users)
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-users mailing list  
> > swift-users@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-users](https://lists.swift.org/mailman/listinfo/swift-users)

---

<div class="post-metadata">

**Author:** ![marco.masser](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/marco.masser/32/6010_2.png) [@marco.masser](https://forums.swift.org/u/marco.masser)\
**Post date:** [September 28, 2017, 9:21am UTC](https://forums.swift.org/t/how-do-you-declare-a-custom-nsattributedstringkey-in-objective-c-for-swift-use/6727/5 "2017-09-28T09:21:10Z")

</div>

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
> > > 
> > > &nbsp;&nbsp;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 {  
> > > > &nbsp;&nbsp;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:  
> > > > [https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift\_name-attribute](https://github.com/apple/swift-evolution/blob/master/proposals/0044-import-as-member.md#swift_name-attribute)
> > > > 
> > > > 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 {  
> > > > &nbsp;&nbsp;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](https://lists.swift.org/mailman/listinfo/swift-users)
> > > 
> > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > swift-users mailing list  
> > > swift-users@swift.org  
> > > [https://lists.swift.org/mailman/listinfo/swift-users](https://lists.swift.org/mailman/listinfo/swift-users)
