В чем преимущество вызова beginUpdates/endUpdates для UITableView, а не для этого?
У меня есть массив массивов, которые я использую для источника данных в виде таблицы. В один момент времени мне может потребоваться внести некоторые сложные изменения в эту структуру данных. (Например, последовательность операций, которые мне могут потребоваться: удалить строку здесь, вставить туда строку, вставить здесь раздел, удалить другую строку, вставить другую строку, удалить другую строку, вставить другой раздел - вы получите идея.) Это легко сделать, если для каждой операции в последовательности я просто обновляю источник данных, а затем немедленно делаю соответствующее обновление для табличного представления. Другими словами, псевдокод будет выглядеть так:
[arrayOfArrays updateForOperation1];
[tableView updateForOperation1];
[arrayOfArrays updateForOperation2];
[tableView updateForOperation2];
[arrayOfArrays updateForOperation3];
[tableView updateForOperation3];
[arrayOfArrays updateForOperation4];
[tableView updateForOperation4];
// Etc.
Однако, если бы я должен был окружать эти операции в блоке beginUpdates/endUpdates, этот код больше не работает. Чтобы понять, почему, изображение начинается с пустого табличного представления и вставляет четыре строки поочередно в начале первого раздела. Здесь псевдокод:
[tableView beginUpdates];
[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];
[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];
[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];
[arrayOfArrays insertRowAtIndex:0];
[tableView insertRowAtIndexPath:[row 0, section 0]];
[tableView endUpdates];
Когда вызывается endUpdates, в представлении таблицы обнаруживается, что вы вставляете четыре строки, все сталкивающиеся в строке 0!
Если мы ДЕЙСТВИТЕЛЬНО хотим, чтобы часть beginUpdates/endUpdates содержала код, нам нужно сделать что-то сложное. (1) Мы делаем все обновления для источника данных без обновления табличного представления по мере продвижения. (2) Мы выясним, как части источника данных до того, как все обновления будут сопоставляться с частями источника данных после всех обновлений, чтобы выяснить, какие обновления нам нужно выполнить для представления таблицы. (3) Наконец, обновите представление таблицы. Псевдокод выглядит примерно так, чтобы выполнить то, что мы пытались сделать в предыдущем примере:
oldArrayOfArrays = [self recordStateOfArrayOfArrays];
// Step 1:
[arrayOfArrays insertRowAtIndex:0];
[arrayOfArrays insertRowAtIndex:0];
[arrayOfArrays insertRowAtIndex:0];
[arrayOfArrays insertRowAtIndex:0];
// Step 2:
// Comparing the old and new version of arrayOfArrays,
// we find we need to insert these index paths:
// @[[row 0, section 0],
// [row 1, section 0],
// [row 2, section 0],
// [row 3, section 0]];
indexPathsToInsert = [self compareOldAndNewArrayOfArraysToGetIndexPathsToInsert];
// Step 3:
[tableView beginUpdates];
for (indexPath in indexPathsToInsert) {
[tableView insertIndexPath:indexPath];
}
[tableView endUpdates];
Почему все это ради beginUpdates/endUpdates? В документации говорится использовать beginUpdates и endUpdates, чтобы сделать две вещи:
- Анимировать несколько операций вставки, удаления и других операций.
- "Если вы не совершаете вызовы вставки, удаления и выбора внутри этого блока, атрибуты таблицы, такие как количество строк, могут стать недействительными". (Что это значит в действительности?)
Однако, если я не использую beginUpdates/endUpdates, представление таблицы похоже на то, что оно анимирует различные изменения одновременно, и я не думаю, что внутренняя согласованность таблицы выглядит поврежденной. Итак, в чем преимущество выполнения сложного подхода с помощью beginUpdates/endUpdates?
Ответы
Ответ 1
Каждый раз, когда вы добавляете/удаляете элемент таблицы, вызывается метод tableView:numberOfRowsInSection:
- если вы не окружите эти вызовы с помощью begin
/endUpdate
. Если элементы массива и таблицы не синхронизированы, без вызовов begin/end будет выбрано исключение.