Uli's Web Site
[ Zathras.de - Uli's Web Site ]
Other Sites: Stories
Pix
Abi 2000
Stargate: Resurgence
Lost? Site Map!
 
 
     home | articles | moose | programming | articles >> blog

 Blog
 
 Blog Topics
 
 Archive
 

15 Most Recent [RSS]

 Uli's source code is on Github!
2010-03-05 @986
 
 Downtime on Friday
2010-03-04 @025
 
 Hacking the Press - A point for usability in press kits
2010-02-18 @404
 
 So. Git.
2010-02-15 @498
 
 Helpful Xcode User Scripts
2010-02-14 @485
 
 CocoaHeads München: Xcode Tiefergelegt Folien
2010-02-10 @995
 
 Debugging Assembler on Mac OS X
2010-02-07 @600
 
 The iPad
2010-01-29 @417
 
 Double click is a shortcut
2010-01-16 @621
 
 Removing transparency from NSImage
2010-01-16 @581
 
 Garbage collection, work of the devil?
2009-12-20 @881
 
 Let's talk about Coding Style
2009-12-15 @459
 
 The iPhone Reality Show
2009-12-13 @589
 
 The Sinus Curve of Life
2009-11-26 @430
 
 AppleScripting Cocoa a little
2009-11-26 @003
 

More...

Safe key-value-coding

Daniel Kennett recently posed the question on Twitter how many of us were defining symbolic constants for use with Key-Value-Coding and Key-Value-Observing. After all, string literals are bad, because they don't get checked by the compiler, so any typo in them goes unnoticed until you realize your key-value-observer method is not called, or you're getting back nil where a property really contains a value.

That immediately sent me musing that it would be nice to have something like @selector() for specifying properties as NSStrings. The nice part about @selector() is that, given you've turned on the Undeclared Selector warning (-Wundeclared-selector), it will complain if given any selector that the compiler doesn't know about yet. Which is usually the case if you make a typo.

Five hours later, the idea suddenly came to me: A property's getter is a selector! And @selector() already does the checking and presents an error message. And one can use NSStringFromSelector() to generate an NSString from any selector. Now, those two are a little wordy, but you can condense that into a neat little macro:

#define PROPERTY(propName)    NSStringFromSelector(@selector(propName))
Admitted, this burns a few additional cycles because it turns a string constant into a function call, but NSStringFromSelector() can probably take an existing string constant from inside the SEL data structure, and you can always take it out of your release builds by writing:
#if DEBUG
#define PROPERTY(propName)    NSStringFromSelector(@selector(propName))
#else
#define PROPERTY(propName)    @#propName
#endif
This turns your property name into the string constant we all know and love in release builds, but does the checking in your debug builds (if you've set up your debug builds with a -DDEBUG=1 flag like many people do).

The advantage of this is that you get checked selectors, even when doing key-value-coding and key-value-observing, without any performance impact on your users. If performance is a problem, you can even only use the checked version of PROPERTY() in a special 'tests' build of your app. But of course then you can still find yourself flummoxed at a missing KVO notification until you do that special build and it complains.

I've added this code to my UKHelperMacros collection of macros, which is available on my source code page.

PS - Thanks to Rob Rix for reminding me of the existence of the # operator, and Jens Ayton for looking up the warning name just when I started wondering why I was getting the warning in one project, but not the other.

Reader Comments: (RSS Feed)
Mike Abdullah writes:
I suppose there is one downside: If you've got a scenario like this: - (BOOL)isEditable; - (void)setEditable:(BOOL)flag; The key is "editable" but there's no @selector(editable) already in existence.
DavidPhillipOster writes:
I couldn't get -Wundeclared-selector to work in a program that also had a few .c files. I filed a bug about it ( http://openradar.appspot.com/7289608 ) . Do you have any suggestions?
Uli Kusterer replies:
Have you tried just checking the "undeclared selectors" checkbox? That will only apply the setting to .m and .mm files, and not to .c files. If you add it to the OTHER_CFLAGS, of course it'll end up in C as well. I do wonder whether there's an OTHER_OBJCFLAGS, though...
Uli Kusterer replies:
Mike, yes, properties with customized getter names are one downside. Also, this won't work for key paths, only for single keys. One could probably create macros that generate a key path, but that would use commas and would have to be a macro like KEYPATH3(foo,bar,baz) instead of just @property(foo.bar.baz).
Ben Cohen writes:
This is useful. Thanks. I wish there was a way to use constants in Interface Builder. I've lost count of the number of times I've had KVO related errors due to miss typing key paths in IB.
Uli Kusterer replies:
Ben, have you filed a bug about this with Apple? I have. Add your voice to the list of people asking for it, it'll increase the likelihood of actually getting it. Besides, it's probably a nice project for an Apple intern.
Comment on this article:
Name:
E-Mail: (not shown, hashed for Gravatar)
Web Site URL: (optional)
Comment: (plain text only)
Please Enter the following word:
Or E-Mail Uli privately.

 
Created: 2009-10-09 @972 Last change: 2010-03-12 @377 | Home | Admin | Edit
© Copyright 2003-2010 by M. Uli Kusterer, all rights reserved.