Actually, I asked a same question before, but I have not found a way to fix it yet, so here I comes again.
My situation:
I have a UIPickerView
with 2 related components, and the number and content of the rows in the 2nd or right components changes with the currently selected row in the 1st or left component, which is a quite common and useful function of UIPickerView
.
Now, if I use 2 thumbs to scroll both components together, my app gets crashed very easily and soon with the information below:
*** Terminating app due to uncaught exception of class '_NSZombie_NSException'
libc++abi.dylib: terminate called throwing an exception
The ironic thing is that, I can't debug it.
Actually, if I add a break point in the pickerView:didSelectRow:inComponent
method, I can't even scroll both components quickly together since it would stop at the break point every time I just put my finger on the screen.
I can only guess the reason is that when the 1st component is being scrolled, the supposed number of rows in 2nd component keeps changing, but meantime, the UIPickerView
is asking for the title and number for the 2nd component, then it crashes.
But I haven't found any method that can be used to judge whether a component is being scrolled. So I can't find the correct time to reject the request of the pickerView
's delegate
and dataSource
for the 2nd component.
Did anyone meet similar situation?
Thanks for your help! I'd appreciate it a lot!
In my code, the bug is about the typePicker
, so I deleted all other codes that is not related to typePicker
.
Here, type
and detailTypes
are two entities in Core Data, and a to-many relationship called details
reaches from type
to detailsTypes
.
If the type is "Nations", for example, the detailTypes
would be "the U.S.", "France", "China", and so on.
So in the typePicker
, the 1st or left components show all type entities, and the 2nd or right components show the corresponding detailTypes
entities according to the currently selected type in 1st component.
And the 1st row of both components in typePicker
is always "None", to allow users not to select a specific type, which is why there is many "+1" in the code.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
if (pickerView == self.typePicker)
return 2;
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
NSUInteger majorTypeRow = [self.typePicker selectedRowInComponent:0] - 1;
if (pickerView == self.typePicker) {
if (component == 0)
return [self.types count] + 1;
else {
if (majorTypeRow == -1) // no major type entities
return 1;
NSString *majorTypeName = [[self.types objectAtIndex:majorTypeRow] name];
NSArray *detailType = [self.detailTypes objectForKey:majorTypeName];
if (detailType)
return [detailType count] + 1;
else {
NSManagedObject *majorType = [self.types objectAtIndex:majorTypeRow];
NSSet *minorTypes = [majorType valueForKey:@"details"];
NSSortDescriptor *sd = [[NSSortDescriptor alloc] initWithKey:@"order" ascending:NO];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sd, nil];
NSArray *array = [minorTypes sortedArrayUsingDescriptors:sortDescriptors];
[self.detailTypes setObject:array forKey:majorTypeName];
[sd release];
return [array count] + 1;
}
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
NSUInteger majorTypeRow = [self.typePicker selectedRowInComponent:0] - 1;
row--;
if (pickerView == self.typePicker) {
if (component == 0)
[pickerView reloadComponent:1]; // I believe this is where the bug starts, but I can't find the exact line of code that causes the crash
else {
if (row == -1)
self._detailType = nil;
else {
NSString *majorTypeName = [[self.types objectAtIndex:majorTypeRow] name];
NSArray *dt = [self.detailTypes objectForKey:majorTypeName];
if (dt)
self._detailType = [dt objectAtIndex:row];
}
}
}
NSIndexPath *path = [self.tableView indexPathForSelectedRow];
[self.tableView reloadData];
[self.tableView selectRowAtIndexPath:path animated:YES scrollPosition:UITableViewScrollPositionNone];
}