Моя базовая модель данных имеет две сущности: Author
и Book
с отношением «ко-многим» (один автор -> много книг).В главном окне я отображаю список книг, где каждая ячейка содержит название книги и имя автора.Представление также разделено на разделы, где каждый заголовок раздела является именем автора.(обратите внимание, что «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 sections]
все еще содержит старые имена авторов?Пожалуйста, помогите!
Обновление # 1
Этот раздел относится к Ответу № 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
объектов при изменении Автор NSManagedObject
?
Так что это приводит к паре вопросов:
Как выизменение имени автора в этом другом виде?
Код для изменения имени автора написан выше в saveAuthorName
.Последовательность действий в приложении выглядит следующим образом:
В основной UITableView
выберите ячейку книги, открывающую новый вид книги с помощью контроллера навигации.
В представлении книги выберите автора выбора, который открывает новое представление выбора автора с помощью контроллера навигации.(все авторы перечислены в UITableView
)
В представлении выбора автора выберите любого автора, открывающего новое представление редактирования автора с помощью контроллера навигации.
В представлении «Редактирование-Автор» измените имя автора и сохраните его, чтобы закрыть представление и перенести предыдущее представление («Выбор-Автор») в стек контроллера навигации.
Теперь возможновыберите другого автора и отредактируйте его и т. д. до закрытия этого представления.(Приносит вид книги)
Вид закрытия книги, выводит на основной вид, где отображаются все книги.
Имя автора в ячейке старое или просто заголовок раздела?
Ячейка прекрасно обновлена с именем автора (благодаря willChangeValueForKey
и didChangeValueForKey
, названным в saveAuthorName
).Только заголовок раздела старый.
Как выглядят ваши методы делегата?
Не могли бы вы указать, какой именно?Я написал все методы делегата, которые выглядят важными для меня в приведенном выше разделе кода.Это включает в себя:
Требуется ли какой-либо другой метод?
Вы уверены, что ваш - [UITableViewDatasource tableView: titleForHeaderInSection:] срабатывает после того, как вы вернетесь из редактирования?
100% уверен.titleForHeaderInSection
возвращает старые значения и вызывается после сохранения изменений.(cellForRowAtIndexPath
также вызывается после сохранения изменений, но приносит новые значения)
Какие методы NSFetchedResultsControllerDelegate запускаются при возврате?
Если вы имеете в виду после сохранения (означает, что после вызова saveAuthorName
будут вызваны следующие методы:
controllerWillChangeContent:
(не используется, только для отладочной информации)
controller:didChangeObject:
(не используется, только для отладочной информации)
controllerDidChangeContent:
Если вы имеете в виду по возвращении к основному виду (означает закрытие вида Книги) следующие вызываемые методы:
Я ценю вашу помощь.Спасибо!
Обновление # 2
Вы реализуете -controller: didChangeSection: atIndex: forChangeType :?
Да, но не меняется при изменении имени автора.Текущая конфигурация для NSFetchedResultsController
выглядит следующим образом:
- Объект: Книга
- Дескриптор сортировки: author.name
- sectionNameKeyPath: author.name
Изменение названия книги (а не имени автора) вызовет событие didChangeSection
, когда NSFetchedResultsController
настроен следующим образом:
- Объект: Книга
- СортировкаДескриптор: name
- sectionNameKeyPath: name
Это означает, что делегат правильно подключен к NSFetchedResultsController.
Это выглядит как вызов [book willChangeValueForKey:@"author"]
и [book didChangeValueForKey:@"author"]
при изменении имени автора недостаточно для NSFetchedResultsController
для отслеживания изменений раздела.