Я хочу использовать изящные вызовы перемещения строки -iOS 5 для анимации представления таблицы в соответствии с некоторыми изменениями состояния модели вместо старого стиля -удаления -и вставки -.
Изменения могут включать как переупорядочение, так и обновление места -, и я хочу анимировать и то, и другое, поэтому для некоторых строк потребуется reloadRowsAtIndexPaths
.
Но! UITableView
кажется просто неправильным в обработке перезагрузки строк при наличии перемещений, если обновленная ячейка смещает позицию из-за перемещений. Используя старые вызовы удаления + вставки,таким образом, который должен быть эквивалентен, работает нормально.
Вот код; Прошу прощения за многословие, но он компилируется и запускается. Мясо находится в методе doMoves:
. Экспозиция ниже.
#define THISWORKS
@implementation ScrambledList // extends UITableViewController
{
NSMutableArray *model;
}
- (void)viewDidLoad
{
[super viewDidLoad];
model = [NSMutableArray arrayWithObjects:
@"zero",
@"one",
@"two",
@"three",
@"four",
nil];
[self.navigationItem setRightBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:
#ifdef THISWORKS
@"\U0001F603"
#else
@"\U0001F4A9"
#endif
style:UIBarButtonItemStylePlain
target:self
action:@selector(doMoves:)]];
}
-(IBAction)doMoves:(id)sender
{
int fromrow = 4, torow = 0, changedrow = 2; // 2 = its "before" position, just like the docs say.
// some model changes happen...
[model replaceObjectAtIndex:changedrow
withObject:[[model objectAtIndex:changedrow] stringByAppendingString:@"\u2032"]];
id tmp = [model objectAtIndex:fromrow];
[model removeObjectAtIndex:fromrow];
[model insertObject:tmp atIndex:torow];
// then we tell the table view what they were
[self.tableView beginUpdates];
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:changedrow inSection:0]]
withRowAnimation:UITableViewRowAnimationRight]; // again, index for the "before" state; the tableview should figure out it really wants row 3 when the time comes
#ifdef THISWORKS
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:fromrow inSection:0]]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:torow inSection:0]]
withRowAnimation:UITableViewRowAnimationAutomatic];
#else // but this doesn't
[self.tableView moveRowAtIndexPath:[NSIndexPath indexPathForRow:fromrow inSection:0]
toIndexPath:[NSIndexPath indexPathForRow:torow inSection:0]];
#endif
[self.tableView endUpdates];
}
#pragma mark - Table view data source boilerplate, not very interesting
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return model.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@""];
if (cell == nil)
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@""];
[cell.textLabel setText:[[model objectAtIndex:indexPath.row] description]];
[cell.detailTextLabel setText:[NSString stringWithFormat:@"this cell was provided for row %d", indexPath.row]];
return cell;
}
Что делает код :устанавливает крошечную модель (небольшой изменяемый массив ); когда кнопка нажата, она вносит небольшое изменение в средний элемент списка и перемещает последний элемент на первый. Затем он обновляет представление таблицы, чтобы отразить эти изменения. :перезагружает среднюю строку, удаляет последнюю строку и вставляет новую нулевую строку.
Это работает. На самом деле, добавление ведения журнала к cellForRowAtIndexPath
показывает, что, хотя я прошу перезагрузить строку 2, табличное представление правильно запрашивает строку 3 из-за вставки, как только пришло время выполнить обновление. Ура!
Теперь закомментируйте верхний #ifdef, чтобы вместо этого использовать вызов moveRowAtIndexPath.
Теперь tableview удаляет строку 2, запрашивает новую строку 2(неправильный! ), и вставляет в последнюю строку -2 позицию (тоже неправильно! ). Конечным результатом является то, что строка 1 переместилась вниз на два слота вместо одного, и прокрутка ее за пределы экрана для принудительной перезагрузки показывает, как она вышла из синхронизации с моделью. Я мог бы понять, если бы moveRowAtIndexPath
изменил частную модель табличного представления в другом порядке, требуя использования «новых» вместо «старых» путей индекса при перезагрузке или выборке модели, но это не то, что происходит. Обратите внимание, что на второй картинке «после» третья и четвертая строки расположены в противоположном порядке, чего не должно происходить независимо от того, какую ячейку я перезагружаю.
Мой словарный запас обогатился проклятиями Apple. Должен ли я вместо этого проклинать себя? Являются ли перемещения строк просто несовместимыми с перезагрузкой строк в том же блоке обновлений (, а также, как я подозреваю, вставками и удалениями )? Может ли кто-нибудь просветить меня, прежде чем я отправлю отчет об ошибке?