我的情况:
我有一个带有2个相关组件的UIPickerView,第二个或右侧组件中行的数量和内容随第一个或左侧组件中当前选定的行而变化,这是UIPickerView的一个非常常见且有用的功能.
现在,如果我使用2个拇指将两个组件一起滚动,我的应用程序很容易崩溃,很快就会有以下信息:
*** Terminating app due to uncaught exception of class '_NSZombie_NSException' libc++abi.dylib: terminate called throwing an exception
具有讽刺意味的是,我无法调试它.
实际上,如果我在pickerView:didSelectRow:inComponent方法中添加一个断点,我甚至无法快速滚动两个组件,因为每次我将手指放在屏幕上它都会在断点处停止.
我只能猜测原因是当滚动第一个组件时,第二个组件中假定的行数不断变化,但同时,UIPickerView要求第二个组件的标题和编号,然后崩溃.
但我还没有找到任何可用于判断组件是否正在滚动的方法.所以我找不到正确的时间来拒绝pickerView的委托和第二个组件的dataSource的请求.
有没有人遇到类似的情况?
谢谢你的帮助!我很感激!
在我的代码中,bug是关于typePicker的,所以我删除了与typePicker无关的所有其他代码.
这里,type和detailTypes是Core Data中的两个实体,称为details的多对多关系从type到detailsTypes.
例如,如果类型是“Nations”,则detailTypes将是“美国”,“法国”,“中国”等.
因此在typePicker中,第一个或左侧组件显示所有类型实体,第二个或右侧组件根据第一个组件中当前选择的类型显示相应的detailTypes实体.
并且typePicker中两个组件的第一行始终为“None”,以允许用户不选择特定类型,这就是代码中有很多“1”的原因.
- (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]; }崩溃是由于您的代表中的这一行
NSUInteger majorTypeRow = [self.typePicker selectedRowInComponent:0] - 1;
正如其他人指出的那样,您需要保留两个单独的数组或对象,这些数组或对象可以为各个组件提供dataSource.
你有一个majorType和detailType.您可以拥有一系列majorTypes和selectedMajorType.保留额外的selectedMajorType消除了使用selectedRowInComponent的需要:并且不再崩溃应用程序.
#pragma mark - UIPickerViewDataSource - (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView { return 2; } - (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component { NSInteger rows = 0; if (component) { rows = [self.selectedMajorType.minorTypes count]; }else{ rows = [self.majorTypes count]; } return rows+1; }
UIPickerViewDelegate实现
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component { row--; NSString *title = @"None"; if (component) { NSArray *minorTypes = [self.selectedMajorType.minorTypes allObjects]; if (row >= 0 && row < [minorTypes count]) { MinorType *minorType = minorTypes[row]; title = minorType.name; } }else{ if(row>=0 && row < [self.majorTypes count]){ MajorType *majorType = self.majorTypes[row]; title = majorType.name; } } return title; } - (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component { row--; if (component==0) { if (row >= 0 && row < [self.majorTypes count]) { self.selectedMajorType = self.majorTypes[row]; }else { self.selectedMajorType = nil; } [pickerView reloadComponent:1]; } }
Demo Source Code