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:
February 23rd, 2008 at 16:30
Thanks you, I found what I was looking for!
November 21st, 2008 at 19:20
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.
November 24th, 2008 at 11:23
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:
and
June 26th, 2013 at 12:02
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