PrEV
Thoughts from a NeXTStep Guy on Cocoa Development

NSUnknownKeyException

May 20, 2009 by Bill Dudney

Over in the book's forums I've gotten several questions about 'setValue:forUndefinedKey:'. They usually take the form of something like this.

Hey my app crashes with the following error.

... * Terminating app due to uncaught exception 'NSUnknownKeyException', reason: 
    '[ setValue:forUndefinedKey:]: 
    this class is not key value coding-compliant for the key someKey.'

What this message is trying to tell you (and I promise once you solve it once it makes total sense) is that the instance of MyViewController does not have a property called 'someKey'.

You have a couple of ways to figure out what the problem is. My favorite is to set a symbolic breakpoint on -[NSObject setValue:forUndefinedKey:]. To do that on the GDB command line type 'b -[NSObject setValue:forUndefinedKey:]'. To do that in the debugger double click on the 'add symbolic breakpoint' entry and paste in '-[NSObject setValue:forUndefinedKey:]' without the quotes.

Run your program again and when it breaks at your breakpoint look up the stack trace and you will likely see that one of your nib files is being loaded (other things could be causing this issue but if you are using them then you probably don't need this blog post). This clues you in that you have a problem in one of your nib files. Here is the stack trace from the simple example I cooked up.

(gdb) bt
#0  0x305bdcb6 in -[NSObject(NSKeyValueCoding) setValue:forUndefinedKey:] ()
#1  0x30529298 in _NSSetUsingKeyValueSetter ()
#2  0x30528ce5 in -[NSObject(NSKeyValueCoding) setValue:forKey:] ()
#3  0x30ab59b0 in -[UIRuntimeOutletConnection connect] ()
#4  0x3026230f in -[NSArray makeObjectsPerformSelector:] ()
#5  0x30ab44b2 in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:] ()
#6  0x30ab64b3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:] ()
#7  0x30976757 in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#8  0x30974e33 in -[UIViewController loadView] ()
#9  0x30974d19 in -[UIViewController view] ()
#10 0x00002889 in -[GimpyAppDelegate applicationDidFinishLaunching:] (self=0xd18280, _cmd=0x9026b944, application=0xd12c00) at /tmp/Gimpy/Classes/GimpyAppDelegate.m:21
#11 0x308f8802 in -[UIApplication _performInitializationWithURL:sourceBundleID:] ()
#12 0x30901935 in -[UIApplication _runWithURL:sourceBundleID:] ()
#13 0x308fec73 in -[UIApplication handleEvent:withNewEvent:] ()
#14 0x308faac2 in -[UIApplication sendEvent:] ()
#15 0x30901121 in _UIApplicationHandleEvent ()
#16 0x32054375 in PurpleEventCallback ()
#17 0x30245560 in CFRunLoopRunSpecific ()
#18 0x30244628 in CFRunLoopRunInMode ()
#19 0x308f904c in -[UIApplication _run] ()
#20 0x30901f2e in UIApplicationMain ()
#21 0x00002834 in main (argc=1, argv=0xbffff11c) at /tmp/Gimpy/main.m:14

Notice that in the stack trace on the 5th and 6th frames we are loading a nib file. You can find out which one in particular but going up the stack frame 6 frames and printing the first argument like this.

(gdb) up 6
#6  0x30ab64b3 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:] ()
(gdb) po *(id*)($ebp + 16)
GimpyViewController

$ebp is the frame pointer and 16 bytes from the frame pointer is the first argument (this varies by hardware env, i was running in the simulator). So as you can see from this bit of GDB goodness our nib file of doom is 'GimpyViewController'. Open your file of doom and you should see something like this.

Notice the little yellow warning symbol in the bottom right hand side of the window. Double click on that and you should see something that looks like this.

If you double click on the error it will bring up a transparent window with the problematic connection highlighted in yellow. Delete that connection and you should be error free.

Now you might be asking 'how did that error get there'. In my case I added an IBOutlet to the GimpyViewController then made a connection in IB. Some time later I deleted the property that had the IBOutlet marker on it but never deleted the connection in IB. It also often happens that an IBOutlet adorned property is renamed without using the refactoring support built into Xcode.

You might also be wondering why this happens. As nib files are loaded they use KVC to make the connections that you specify. Which basically invokes a method like this [sourceObject setValue:destinationObject forKey:@"zippy"] where source object in this case is the GimpyViewController instance and the destination object is the text field that the view controller was connected to. When the setValue:forKey: method can't find the set method for the key (i.e. setZippy: in this case) it calls the setValue:forUndefinedKey: method giving the object one last chance to fix the error. If the object does not have a custom implementation of this method (i.e. NSObject's implementation is used) and error is thrown and you get the error message.

Hope this helps you get beyond this error message.



Comments:

found my problem,

with a tabbarcontroller you need to set the type of controller in the xib.
Default is UIViewController, but it has to be your xxxViewController.

otherwise you get the same message.

tnx for eliminating my bugs !

Joachim

Posted by Joachim on July 28, 2009 at 08:35 AM MDT #

thank you !

I didn't saw this yet.
I have this error while i don't have a warning symbol.
Still something i don't see yet about connections and outlets or so.

but tnx for writing this !

Posted by Joachim on July 28, 2009 at 08:35 AM MDT #

Big thanks! Your post was very helpful!

Posted by Ken Pespisa on October 06, 2010 at 10:49 PM MDT #

thanx a lot 4 the fine solution.

Posted by prabir kr dutta on December 12, 2010 at 10:29 AM MST #

Post a Comment:
  • HTML Syntax: Allowed