У меня тут ситуация, и я теряю волосы ...
Очень простое приложение, управляемое базовыми данными, которое имеет контроллер табличного представления с кнопкой навигации добавления. Это очень похоже на образец рецептов, с парой различий
- В модели имеется только один объект с двумя атрибутами
- Ячейка в главной таблице не настроена, используется текстовая метка по умолчанию
С основной частью данных все в порядке, поскольку новая запись добавляется в базовое хранилище и извлекается с использованием контроллера полученных результатов. Проблема возникает, когда я добавляю новый элемент, который будет размещен в верхней части списка. Это может быть, например, новый элемент в пустом списке или элемент с порядком сортировки, поднимающий его наверх. Элемент, который находится сверху, не виден! Ячейка там с текстовой меткой nil, однако я ясно видел, что извлеченный контроллер результатов выдает уведомление об обновлении, и я настроил ячейку, обновляя ее новым текстом.
Единственный способ сделать эту ячейку для отображения - это прокрутить таблицу данных, чтобы вызвать cellForRowAtIndexPath
, затем текст элемента обновится. Я добавляю еще один элемент, который будет помещен сверху, снова текст нового элемента не виден. Я добавляю элемент, который будет располагаться внизу - нет проблем, текст в ячейке виден. Также изначально, когда я просто запускаю приложение, проблем нет, все элементы видны.
Не уверен, что кто-то может помочь решить загадку без исходного кода, но все же надеюсь получить некоторые подсказки о том, как отлаживать ... Я попытался сравнить вызовы делегатов с приложением Receipe, и все то же самое.
UPD:
- (void)configureCell:(UITableViewCell *)cell
atIndexPath:(NSIndexPath *)indexPath
{
Word* word = (Word*)[fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = word.word;
printf("configureCell: %d : \"%s\"\n", indexPath.row,
[word.word cStringUsingEncoding:NSASCIIStringEncoding]);
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = @"Cell";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc]
initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:CellIdentifier] autorelease];
}
[self configureCell:cell atIndexPath:indexPath];
return cell;
}
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView beginUpdates];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
{
[self.tableView endUpdates];
}
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type newIndexPath:(NSIndexPath *)newIndexPath {
UITableView *tableView = self.tableView;
switch(type) {
case NSFetchedResultsChangeInsert:
printf("didChangeObjectAtRow: %d: insert\n", newIndexPath.row);
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
printf("didChangeObjectAtRow: %d : delete\n", indexPath.row);
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
printf("didChangeObjectAtRow: %d : update\n", indexPath.row);
[self configureCell:[tableView cellForRowAtIndexPath:indexPath] atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
printf("didChangeObjectAtRow: %d / %d : move\n", indexPath.row, newIndexPath.row);
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath] withRowAnimation:UITableViewRowAnimationFade];
break;
}
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
NSInteger count = [[fetchedResultsController sections] count];
if (count == 0)
{
count = 1;
}
printf("number of sections: %d\n", count);
return count;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSInteger numberOfRows = 0;
if ([[fetchedResultsController sections] count] > 0)
{
id <NSFetchedResultsSectionInfo> sectionInfo = [[fetchedResultsController sections] objectAtIndex:section];
numberOfRows = [sectionInfo numberOfObjects];
}
printf("number of rows in sections: %d is %d\n", section, numberOfRows);
return numberOfRows;
}
- (NSFetchedResultsController*)fetchedResultsController
{
if(fetchedResultsController != nil)
return fetchedResultsController;
// This is autoreleased as the name implies
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Word" inManagedObjectContext:managedObjectContext];
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
NSSortDescriptor* sortByWordDescriptor = [[NSSortDescriptor alloc] initWithKey:@"word" ascending:YES];
NSArray* sortArray = [[NSArray alloc] initWithObjects:sortByWordDescriptor, nil];
[fetchRequest setSortDescriptors:sortArray];
NSFetchedResultsController* controller = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:managedObjectContext sectionNameKeyPath:nil cacheName:@"Hmm"];
controller.delegate = self;
self.fetchedResultsController = controller;
[fetchRequest release];
[sortByWordDescriptor release];
[sortArray release];
[controller release];
return fetchedResultsController;
}
- (void) add:(id)sender
{
WordzWordEditView *wordEditViewController = [[WordzWordEditView alloc] initWithNibName:@"WordzWordEditView" bundle:nil];
wordEditViewController.delegate = self;
Word* word = [NSEntityDescription insertNewObjectForEntityForName:@"Word" inManagedObjectContext:self.managedObjectContext];
wordEditViewController.word = word;
UINavigationController *editWordNavigationController = [[UINavigationController alloc] initWithRootViewController:wordEditViewController];
[self presentModalViewController:editWordNavigationController animated:YES];
[wordEditViewController release];
[editWordNavigationController release];
}
UPD: вывод
controllerWillChangeContent
didChangeObjectAtRow: 0: insert
controllerDidChangeContent
number of sections: 1
number of sections: 1
number of rows in sections: 0 is 2
cellForRowAtIndexPath: 0
configureCell: 0 : "(null)"
post configuring: "(null)"
controllerWillChangeContent
configureCell: 0 : "asd"
didChangeObjectAtRow: 0 : update with 'asd'
controllerDidChangeContent
number of sections: 1
number of sections: 1
number of rows in sections: 0 is 2