UIPickerView падает при прокрутке 2 компонентов вместе

На самом деле, я задавал тот же вопрос раньше, но пока не нашел способа его исправить, так что я снова здесь.

Моя ситуация:

у меня есть UIPickerView с двумя связанными компонентами, а количество и содержание строк во 2-м или правом компонентах изменяется в зависимости от текущей выбранной строки в 1-м или левом компоненте, что является довольно распространенной и полезной функцией UIPickerView,

Теперь, если я использую 2 больших пальца для прокрутки обоих компонентов вместе, мое приложение очень быстро рушится, и вскоре появляется следующая информация:

*** Terminating app due to uncaught exception of class '_NSZombie_NSException'
libc++abi.dylib: terminate called throwing an exception

Ирония в том, что я не могу отладить это.

На самом деле, если я добавлю точку останова в pickerView:didSelectRow:inComponent метод, я не могу даже быстро прокрутить оба компонента, так как он остановится в точке останова каждый раз, когда я просто нажимаю пальцем на экран.

Я могу только догадываться, причина в том, что, когда 1-й компонент прокручивается, предполагаемое количество строк во 2-м компоненте продолжает изменяться, но тем временем UIPickerView запрашивает название и номер для 2-го компонента, а затем вылетает.

Но я не нашел ни одного метода, который можно было бы использовать для оценки прокрутки компонента. Поэтому я не могу найти правильное время, чтобы отклонить запрос pickerView"s delegate а также dataSource для 2-го компонента.

Кто-нибудь сталкивался с подобной ситуацией?

Спасибо за вашу помощь! Я очень ценю это!


В моем коде ошибка о typePicker, поэтому я удалил все остальные коды, не связанные с typePicker,

Вот, type а также detailTypes два объекта в Базовых данных, и отношение ко многим называется details достигает от type в detailsTypes,

Если тип "Наций", например, detailTypes будет "США", "Франция", "Китай" и так далее.

Так что в typePicker1-й или левый компоненты показывают все объекты типа, а 2-й или правый компоненты показывают соответствующие detailTypes объекты в соответствии с текущим выбранным типом в 1-м компоненте.

И 1-й ряд обоих компонентов в typePicker всегда имеет значение "Нет", чтобы позволить пользователям не выбирать конкретный тип, поэтому в коде много "+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];
}

2 ответа

Решение

Сбой из-за этой строки в ваших делегатах

NSUInteger majorTypeRow = [self.typePicker selectedRowInComponent:0] - 1;

Как уже указывалось другими, вам нужно сохранить два отдельных массива или объекта, которые могут предоставить источник данных для соответствующих компонентов.

У вас есть 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];
    }
}

Демо Исходный код

Ладно, думаю, я понимаю проблему:

Проблема с прокруткой двух компонентов заключается в том, что, поскольку ваш источник данных UIPickerView может меняться из-за зависимостей, которые вы создали с отношениями данных. Я думаю, что вам нужно создать два массива, которые представляют левый и правый соответственно и заполнить в зависимости от того, какой компонент вы меняете!

Решение может быть найдено, проверяя подобную проблему здесь! UIPickerView с двумя компонентами падает при прокрутке обоих

Кроме того, что касается проверки того, прокручивает ли ваш UIPickerView, вы можете просто установить таймер. Полезная ссылка здесь: Определение прокрутки UIPickerWheel! Проверяя, совпадают ли текущие строки, вы можете определить (в течение короткого интервала), переместил ли пользователь колесо!

Надеюсь это понятно и полезно!

Другие вопросы по тегам