Monday, January 26, 2009

When you're loading from a nib file, outlets aren't connected until #loadView is called

When you're loading a nib file, the load process is supposed to connect outlets that are set in Interface Builder. And according to the Resource Programming Guide, in the Nib Object Life Cycle section:
When you use the methods of NSNib or NSBundle to load and instantiate the objects in a nib file, the
underlying nib-loading code does the following:
...
3. It reestablishes all connections (actions, outlets, and bindings) between objects in the nib file. This
includes connections to File’s Owner and other proxy objects.
Having read that bit, I assumed that initWithNibName:bundle: would count as one of those "NSNib or NSBundle" methods. Wrong. Instead, the outlets are connected when the view loads. To figure that out, I just wrote the method to set the outlet I cared about (in this case, it's called editableField) and set a breakpoint in the method. It's not until loadView happens - here's the full stack trace:
#0  -[EditTextField setEditableField:] (self=0x10266b0, _cmd=0x2ceb3, f=0x105afd0) at /Users/jamesmoore/dev/CallWrangler/Classes/EditTextField.m:37
#1  0x93ac2cee in -[NSObject(NSKeyValueCoding) setValue:forKey:] ()
#2  0x93b477c1 in -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] ()
#3  0x30c1f907 in -[UIRuntimeOutletConnection connect] ()
#4  0x93e5cc45 in -[NSArray makeObjectsPerformSelector:] ()
#5  0x30c1e455 in -[UINib instantiateWithOptions:owner:loadingResourcesFromBundle:] ()
#6  0x30c204b8 in -[NSBundle(NSBundleAdditions) loadNibNamed:owner:options:] ()
#7  0x30ac6eca in -[UIViewController _loadViewFromNibNamed:bundle:] ()
#8  0x30ac72af in -[UIViewController loadView] ()
#9  0x30ac7421 in -[UIViewController view] ()
#10 0x30acb01d in -[UIViewController(UIViewControllerContentScrollView) contentScrollView] ()
#11 0x30acd415 in -[UINavigationController _startTransition:fromViewController:toViewController:] ()
#12 0x30acdd23 in -[UINavigationController pushViewController:transition:forceImmediate:] ()
#13 0x30acd95d in -[UINavigationController pushViewController:animated:] ()
#14 0x0001f157 in -[SavedListViewController pushEditingViewForListNamed:] (self=0x1035630, _cmd=0x2b9d4, name=0x1040dd0) at /Users/jamesmoore/dev/CallWrangler/Classes/SavedListViewController.m:115
#15 0x0001f72b in -[SavedListViewController tableView:didSelectRowAtIndexPath:] (self=0x1035630, _cmd=0x30c624d0, tableView=0x103a370, indexPath=0x10402f0) at /Users/jamesmoore/dev/CallWrangler/Classes/SavedListViewController.m:182
#16 0x30a8f74d in -[UITableView(_UITableViewPrivate) _sendSelectionDidChange] ()
#17 0x30a96b4c in -[UITableView touchesEnded:withEvent:] ()
#18 0x30a6790f in -[UIWindow sendEvent:] ()
#19 0x30a56ff7 in -[UIApplication sendEvent:] ()
#20 0x30a561d8 in _UIApplicationHandleEvent ()
#21 0x31563dea in SendEvent ()
#22 0x3156640c in PurpleEventTimerCallBack ()
#23 0x93dee5f5 in CFRunLoopRunSpecific ()
#24 0x93deecd8 in CFRunLoopRunInMode ()
#25 0x31564600 in GSEventRunModal ()
#26 0x315646c5 in GSEventRun ()
#27 0x30a4ec98 in -[UIApplication _run] ()
#28 0x30a5a094 in UIApplicationMain ()
#29 0x0001c620 in main (argc=1, argv=0xbffff044) at /Users/jamesmoore/dev/CallWrangler/main.m:33
(gdb)

2 comments:

Edu said...

Hmmm!, exactly the “error” I’m having now… interesting (and unexpected) behaviour.

--edu

Maxcanna said...

Thanks man! This saved me hours of googlin' to solve the prob.