Apple’s Cocoa’s NSTokenField advance use explained

Historically the specification of tokens to be used in custom strings such as file names and report generation was just to use some special character such as ‘%’ or ‘@’ and pair it with some more ore less cryptic token to specify the kind of the replacement, e.g.: ‘%d.4′ or ‘%User’ and other variants such as ‘@day@’.

Of course this is not what today’s end users, especially on Apple Mac OS X want to see. I was already thinking how to make this more comfortable in one ouf our Mac products and with Adobe’s recent Lightroom demo I got an inspiration: Basically they use what Apple introduced with Apple Mail’s address field, rounded visual tokens you can inserted and drag around easily. So I set out to implement this using the NSTokenField, new in OS X 10.4, however I had to find out making it behave as wanted was not as easy as I hoped. One needs quite some Cocoa and ObjC experience to implement normal text intermixed with those rounded tokens and Google was quite sparse on on details and thus I decided to document the details here:

Note I’m not a Cocoa guru - feel free to comment suggestions and improvements!

Of course introducing it in your UI just means dropping it ouf of the Interface Builder’s toolbox into your project. The difficulties begin when you want to control the appearance of the tokens and display some as ordinary text.

For this you need to create your own class and add it to the NSArray that the NSTokenFieldCell uses to hold the tokens. Furthermore you need to define a delegate for the NSTokenField so that this delegate can respond to requests such as:

- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject

and

- (NSTokenStyle)tokenField:(NSTokenField *)tokenField styleForRepresentedObject:(id)representedObject

so you gain control about the formating of the individual tokens and the ordinary text parts can get the default NSPlainTextTokenStyle and you can return NSRoundedTokenStyle as well as the display text for your custom tokens.

When you want a context menu for your tokens you furthermore need to implement:

- (BOOL)tokenField:(NSTokenField *)tokenField hasMenuForRepresentedObject:(id)representedObject

as well as:

- (NSMenu *)tokenField:(NSTokenField *)tokenField menuForRepresentedObject:(id)representedObject

and to allow drag’n drop of your precious tokens your class need to adhere to the NSCoding protocol and implement:

- (void)encodeWithCoder:(NSCoder *)encoder

and

- (id)initWithCoder:(NSCoder *)decoder

and though deprecated you must use the old, non-keyed coding and decoding for this drag’n drop code:

In my example code this just was:

[encoder encodeObject:name];

respective:

name = [[decoder decodeObject] retain];

I hope this is a help for other people that want to use the NSTokenField and find the current Apple documentation slightly lacking detail. The full Xcode project is attached below:

TokenFieldTest

4 Responses to “Apple’s Cocoa’s NSTokenField advance use explained”

  1. Bloodshed Says:

    Thanks you, I found what I was looking for!

  2. Anton Says:

    I don’t know if I am too late with this article…

    But what if we want to drag’n'drop tokents between two NSTokenFields?
    I’ve tried to add another field, but drag’n'dropping turns into just corying the text.

  3. René Says:

    In 10.4 drag’n drop just worked with the above code. Due to the usual random code changes on Apple’s side between 10.4 (Tiger) and 10.5 (Leopard) drag’n drop no longer “just works”. For drag’n drop of NSTokenField token in 10.5 you have to additionally implement:

    - (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard

    and

    - (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard

  4. ashwini Says:

    Hi,

    I implemented this
    (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard

    but drag n drop works as copy paste rather than cut paste.
    I want it to work as is works in Mail.app to field mail address token dragged to cc field.

    Can someone please help me, am I missing something which i need to implement?

    Thanks,
    Ashwini

Leave a Reply

You must be logged in to post a comment.