Автоматически расширять UITableView - NSRangeException - PullRequest
3 голосов
/ 21 сентября 2009

У меня есть база данных SQLite, связанная с моим uitableview. Здесь около 2000 строк, поэтому сначала я получаю 25 строк. Как только я прокручиваю до конца списка, я хочу, чтобы он автоматически получил еще 25 строк.

Вот метод, который я сейчас использую. Не обращайте внимания на то, что произойдет, если я загружу все 2000 строк, об этом я буду беспокоиться позже. В tableView:numberOfRowsInSection: я возвращаю на одну больше, чем загруженные в данный момент строки. Затем в tableView:cellForRowAtIndexPath: я загружаю больше строк, если он загружает последнюю строку.

Обычно я могу получить несколько страниц, но в итоге получаю исключение: *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSCFArray objectAtIndex:]: index (10) beyond bounds (10)'. Индекс всегда 8-10. Я не знаю, что это за массив, но оба моих rows и indices массива содержат более 10 элементов.

tableView:cellForRowAtIndexPath:

if(indexPath.row >= [rows count]) {
    [cell.textLabel setText:@"Loading..."];
    if(!updating && indexPath.row == [rows count]) {
        updating = YES;
        [[self tableView] beginUpdates];
        NSMutableArray *indices = [NSMutableArray array];
        // stmt = ...
        while(sqlite3_step(stmt) == SQLITE_ROW) {
            [rows addObject:@"..."];
            [indices addObject:[NSIndexPath indexPathForRow:[rows count]-1 inSection:0]];
        }
        [[self tableView] insertRowsAtIndexPaths:indices withRowAnimation:UITableViewRowAnimationNone];
        [[self tableView] endUpdates];
        updating = NO;
    }
    return cell;
}

Трассировка стека:

#0  0x01ce4004 in ___TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION___ ()
#1  0x9779df49 in objc_exception_throw ()
#2  0x01cc5c3b in +[NSException raise:format:arguments:] ()
#3  0x01cc5b9a in +[NSException raise:format:] ()
#4  0x00072cc9 in _NSArrayRaiseBoundException ()
#5  0x00010227 in -[NSCFArray objectAtIndex:] ()
#6  0x0047fe5b in -[_UITableViewUpdateSupport(Private) _setupAnimationsForExistingVisibleCells] ()
#7  0x0047f9e0 in -[_UITableViewUpdateSupport initWithTableView:updateItems:oldRowData:newRowData:oldRowRange:newRowRange:context:] ()
#8  0x002eca2b in -[UITableView(_UITableViewPrivate) _updateWithItems:withOldRowData:oldRowRange:newRowRange:context:] ()
#9  0x002ec757 in -[UITableView(_UITableViewPrivate) _endCellAnimationsWithContext:] ()
#10 0x002def56 in -[UITableView endUpdates] ()    

Ответы [ 2 ]

4 голосов
/ 21 сентября 2009

Мне немного непонятно, почему вы вставляете строки. Мне кажется, что вы делаете это немного сложнее, чем нужно. UITableView будет запрашивать только значения для ячеек таблицы, которые находятся на экране (или скоро будут). Более того, непрерывно добавляя строки в табличное представление, полоса прокрутки не отражает фактическую позицию пользователя в наборе данных.

В таком же смысле имеет смысл возвращать общее количество строк в tableView:numberOfRowsInSection: (вы можете использовать агрегатную функцию SQLite COUNT, чтобы сделать это без фактического извлечения всех данных) и при необходимости кэшировать дополнительные данные используя что-то похожее на то, что у вас есть выше), когда вы испытываете «промах кэша».

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

Я бы посоветовал что-то, похожее на это:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    if ([indexPath row] >= [cache count]) {
        // Load additional items into the cache
    }

    // Do the regular cell setup stuff here; you can assume the data you need is available
    return cell;
}
0 голосов
/ 22 сентября 2009

Алекс, я принимаю твой ответ, хотя мне все еще интересно, что вызывает фактическое исключение.

Ваш комментарий об обновлении табличного представления при возврате ячейки привел меня к реализации - (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath для загрузки большего количества строк, когда это необходимо, что более стабильно, хотя я должен сделать это в отдельном потоке, чтобы получить какую-либо производительность.

Ваше решение также работает и, конечно, проще, чем мой текущий метод. Я должен решить, хочу ли я, чтобы полоса прокрутки отображала фактическую позицию или более ощутимую позицию. По крайней мере, для меня такое ощущение, что приложение загружает много объектов, и поэтому работает медленнее, когда полоса прокрутки такая маленькая.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...