Моя модель основных данных имеет две сущности: Автор
и Книга
с отношение ко многим (один автор->много книг). В главном представлении я отображаю список книг, где каждая ячейка содержит название книги и имя автора. Представление также разделено на разделы, где заголовок каждого раздела является именем автора. (обратите внимание, что "author.name" установлено как для дескриптора сортировки, так и для sectionNameKeyPath)
Вот код (упрощенный для ясности):
- (NSFetchedResultsController *)fetchedResultsController {
if (__fetchedResultsController != nil) {
return __fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Book" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc] initWithKey:@"author.name" ascending:YES] autorelease];
NSArray *sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:@"author.name" cacheName:nil] autorelease];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
[self.fetchedResultsController performFetch:&error];
return __fetchedResultsController;
}
- (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];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
}
Book* book = [self.fetchedResultsController objectAtIndexPath:indexPath];
cell.textLabel.text = [NSString stringWithFormat:@"%@ %@", book.name, book.author.name];
return cell;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
- (void)controllerDidChangeContent:(NSFetchedResultsController*)controller {
[self.tableView reloadData];
}
Теперь, если пользователь изменит имя автора, а затем вернется к основному виду, в ячейках и разделах будет отображаться старое имя автора. После поиска в Интернете я нашел следующий код, который устраняет проблему со старыми именами авторов в ячейках, но не в заголовках разделов:
- (void)saveAuthorName:(NSString *)newName {
for (Book* book in author.books) {
[book willChangeValueForKey:@"author"];
}
author.name = newName;
for (Book* book in author.books) {
[book didChangeValueForKey:@"author"];
}
// save changes
NSError * error ;
if( ![self.moc save:&error] ) {
// Handle error
}
}
Почему [разделы self.fetchedResultsController]
все еще содержат старые имена авторов? Пожалуйста помоги!
Этот раздел относится к ответу №1 Маркуса
Хммм, все еще немного неясно. Вы хотите сказать, что количество секций неверно?
Количество секций не изменилось. Неверное содержимое объектов в массиве свойств Sections
.
Основываясь на опубликованном вами коде, вы просто извлекаете экземпляры NSManagedObject из NSFetchedResultsController.Может быть, есть некоторая путаница в том, что это такое?
В коде я извлекаю экземпляры NSManagedObject
из NSFetchedResultsController
для отображения названия книги и имени автора для каждой ячейки таблицы (когда cellForRowAtIndexPath
называется). Однако заголовки каждого раздела в UITableView
, насколько я понимаю, взяты не из NSManagedObject
, а из объекта _NSDefaultSectionInfo
, который реализует NSFetchedResultsSectionInfo
. протокол (при вызове titleForHeaderInSection
).
Я понял это по следующему коду, который я написал для отладки:
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
id mySection = [[fetchedBooks sections] objectAtIndex:section];
NSLog(@"%@", mySection)
return [[[self.fetchedResultsController sections] objectAtIndex:section] name];
}
Результат журнала был <_NSDefaultSectionInfo: 0x8462b90>. Документация NSFetchedResultsController для свойства Sections показывает:
/* Returns an array of objects that implement the NSFetchedResultsSectionInfo protocol.
It's expected that developers use the returned array when implementing the following methods of the UITableViewDataSource protocol
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView;
- (NSInteger)tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section;
*/
Поэтому, пожалуйста, поправьте меня, если я ошибаюсь: _NSDefaultSectionInfo
не является NSManagedObject
, верно? Если да, то как NSFetchedResultsController
может обнаруживать изменения для объектов _NSDefaultSectionInfo
при изменении Author NSManagedObject
?
Таким образом, это приводит к нескольким вопросам:
Как вы меняете имя автора в этом другом представлении?
Код смены имени автора написан выше в saveAuthorName
. Процесс в приложении выглядит следующим образом:
В главном UITableView
выберите ячейку книги, которая открывает новое представление книги с помощью контроллера навигации.
В представлении книги выбор «Выбор автора» открывает новое представление «Выбор автора» с помощью навигационного контроллера. (все авторы перечислены в UITableView
)
В представлении Select-Author выберите любого автора, который открывает новое представление Edit-Author с помощью навигационного контроллера.
В представлении Edit-Author изменение имени автора и сохранение, которое закрывает представление и возвращает предыдущее представление (Select-Author) в стек навигационного контроллера.
Теперь можно выбрать другого автора и отредактировать его и т.д.. до закрытия этого вида. (Открывается вид книги)
Закрытие вида книги приводит к основному виду, где отображаются все книги.
Имя автора в ячейке устарело или это только заголовок раздела?
Ячейка отлично обновляется именем автора (благодаря willChangeValueForKey
и didChangeValueForKey
, вызываемым в saveAuthorName
). Только заголовок раздела старый.
Как выглядят ваши методы делегирования?
Уточните, пожалуйста, какой именно? Я написал все методы делегата, которые кажутся мне важными, в приведенном выше разделе кода. Сюда входят:
cellForRowAtIndexPath
titleForHeaderInSection
controllerDidChangeContent
Требуется ли какой-либо другой метод?
Вы уверены, что ваш -[UITableViewDatasource tableView: titleForHeaderInSection:] срабатывает после того, как вы вернетесь из редактирования?
На 100% уверен. titleForHeaderInSection
приносит старые значения и вызывается после сохранения изменений.(cellForRowAtIndexPath
также вызывается после сохранения изменений, но приносит новые значения)
Какие методы NSFetchedResultsControllerDelegate запускаются при возвращении?
Если вы имеете в виду при сохранении (имеется в виду после вызова saveAuthorName
) вызываются следующие методы:
controllerWillChangeContent:
(не используется, только для информации об отладке)
controller:didChangeObject:
(не используется, только для информации об отладке)
controllerDidChangeContent:
Если вы имеете в виду при возвращении в главное представление ( означает закрытие представления книги) вызываются следующие методы:
cellForRowAtIndexPath
titleForHeaderInSection
numberOfSectionsInTableView
numberOfRowsInSection
Я ценю вашу помощь. Спасибо!
Вы реализуете -controller: didChangeSection: atIndex: forChangeType:?
Да, но не срабатывает при смене имени автора. Текущая конфигурация для NSFetchedResultsController
выглядит следующим образом:
Изменение имени книги (а не автора name) вызовет событие didChangeSection
, когда NSFetchedResultsController
настроен следующим образом:
Что означает, что делегат правильно подключен к NSFetchedResultsController.
Это выглядит как вызов [book willChangeValueForKey:@"author"]
и [book didChangeValueForKey:@"author"]
, когда изменение имени автора недостаточно для NSFetchedResultsController
для отслеживания изменений разделов.