I have a two level UIPickerView which means if user selects the first component, the second component will update its data.
The data should be look like this:
self.type = @[@"fruit", @"airlines"];
self.data = @[@[@"Apple", @"Orange"], @[@"Delta", @"United", @"American"]];
datasource and delegate method:
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 2;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
if(component == 0){
return self.data.count;
}else if(component == 1){
NSInteger row1 = [pickerView selectedRowInComponent:0];
return [self.data[row1] count];
}
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
if(component == 0){
[pickerView reloadComponent:1];
}
NSInteger row1 = [pickerView selectedRowInComponent:0];
NSInteger row2 = [pickerView selectedRowInComponent:1];
// here may crash, some time
NSLog(@"data: %@", self.data[row1][row2]);
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
if(component == 0){
return self.type[row];
}else if(component == 1){
NSInteger row1 = [pickerView selectedRowInComponent:0];
// here may also crash
return self.data[row1][row];
}
}
There are several places which may cause crashes(NSRangeException) in the above code as commented. However, they rarely happened. I haven't gotten this crash yet, but my users had according to Crashlytics report.
I add some codes to validate row1 and row2 before accessing self.data[row1][row2] and send to my server if fail. I found that the value of [pickerView selectedRowInComponent:0] may be incorrect some time. For example, when user changes the first component from "fruit" to "airlines" and select some item in second component, the value of selectedRowInComponent:0 may still be 0(index of "fruit").
I guess this is caused by race condition but how can I solve this?