This is my first time using IB, but after spending a one or two intimate days with it I believe I’m beginning to understand it. That’s just my way of saying I might be overlooking something simple here:
I’ve set up a UIPickerView and joined it to its DataSource and Delegate object in IB (both different Classes in my case). This allows the picker to show up when I run the app, which is very encouraging when it hasn’t been showing up in any previous test runs. 😉 However, when I scroll the UIPickerView, the program crashes, and I can’t find any of my code referenced in the backtrace. After quite a bit of troubleshooting, I think I’ve narrowed down the crash to two distinct cases, as far as the backtrace is concerned:
the return value of -pickerView:numberOfRowsInComponent: > the number of rows displayed
- The app crashes as soon as a motion is begun to select a new row
- The app crashes if I try to use -selectRow:inComponent:animated:
backtrace (ignoring main):
#0 0x955e8688 in objc_msgSend ()
#1 0x0167bea8 in -[UIPickerView table:cellForRow:column:reusing:] ()
#2 0x016773c1 in -[UIPickerView table:cellForRow:column:] ()
#3 0x017fef53 in -[UITable createPreparedCellForRow:column:] ()
#4 0x018077c8 in -[UITable _updateVisibleCellsNow] ()
#5 0x018027cf in -[UITable layoutSubviews] ()
#6 0x03ac42b0 in -[CALayer layoutSublayers] ()
#7 0x03ac406f in CALayerLayoutIfNeeded ()
#8 0x03ac38c6 in CA::Context::commit_transaction ()
#9 0x03ac353a in CA::Transaction::commit ()
#10 0x03acb838 in CA::Transaction::observer_callback ()
#11 0x007b8252 in __CFRunLoopDoObservers ()
#12 0x007b765f in CFRunLoopRunSpecific ()
#13 0x007b6c48 in CFRunLoopRunInMode ()
#14 0x000147ad in GSEventRunModal ()
#15 0x00014872 in GSEventRun ()
#16 0x0168a003 in UIApplicationMain ()
the return value of -pickerView:numberOfRowsInComponent: < the number of rows displayed
- The app crashes after the motion ceases and the row is selected
- The app does not crash if I try to use -selectRow:inComponent:animated:
backtrace (ignoring main):
#0 0x955e8688 in objc_msgSend ()
#1 0x0167700d in -[UIPickerView _sendSelectionChangedForComponent:] ()
#2 0x017f4187 in -[UIScroller _scrollAnimationEnded] ()
#3 0x016f732c in -[UIAnimator stopAnimation:] ()
#4 0x016f7154 in -[UIAnimator(Static) _advance:] ()
#5 0x00017739 in HeartbeatTimerCallback ()
#6 0x007b7ac0 in CFRunLoopRunSpecific ()
#7 0x007b6c48 in CFRunLoopRunInMode ()
#8 0x000147ad in GSEventRunModal ()
#9 0x00014872 in GSEventRun ()
#10 0x0168a003 in UIApplicationMain ()
My delegate and datasource implementations follow:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return (NSInteger)3;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return (NSInteger)4;
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
//it will probably be better to use the method following when creating the rows, so I can better customize it
return @"strings";
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSLog(@"selected a row");
}
Investigated Apple documentation a bit and it proved my previous guess. From Resource Programming Guide:
So the top level objects are created autoreleased and you must retain them in your code. There’s also described recommended way to handle that:
I’ve tested this approach in a sample code – defined outlets for delegate and data source objects in file owner class and connected them in IB. And in file owner class defined a property for those outlets:
Worked fine.