核心数据 - 在对象中的多对关系更改属性后更新 UI
Posted
技术标签:
【中文标题】核心数据 - 在对象中的多对关系更改属性后更新 UI【英文标题】:Core Data - update UI after object in to-many relationship change property 【发布时间】:2014-01-03 23:05:02 【问题描述】:我有一个看起来像这样的核心数据模型:
Author
======
- name
- bio
- books (to-many relationship)
Book
====
- title
- release date
- author (to-one relationship)
我向用户呈现作者的表格视图,每个表格单元格代表一个作者,并显示他的name
和他写的最新一本书的title
。
为了显示作者列表,我使用NSFetchedResultsController
和以下NSFetchRequest
:
NSFetchRequest *request = [[NSFetchRequest alloc] initWithEntityName:@"Author"];
request.predicate = nil;
request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name" ascending:YES]];
request.fetchBatchSize = 20;
我的问题是:
我让用户在另一个屏幕上更改书名,并且我希望如果用户更改那本最新书的标题,作者表视图将更新并反映最近的更改。
如何在作者表视图中更新最新的书名?
【问题讨论】:
【参考方案1】:如果您已经在视图控制器中嵌入了 NSFetchedResultController 并实现了所有委托方法(请参阅前面发布的 Duncan 的回答),那么:
您将您的 VC 订阅到上下文更改通知(viewDidLoad
或 init
)
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(contextUpdated:)
name:NSManagedObjectContextObjectsDidChangeNotification
object:nil];
实现contextUpdated
方法
-(void)contextUpdated:(NSNotification*)notification
// if the context changed on other screens
NSManagedObjectContext *changedContext = notification.userInfo[@"managedObjectContext"];
if ([changedContext isEqual: self.fetchedResultsController.managedObjectContext])
[_tableView reloadData];
确保您从通知中取消订阅您的 VC
-(void)dealloc
[[NSNotificationCenter defaultCenter] removeObserver:self];
【讨论】:
【参考方案2】:在 tableViewController 中实现 fetchedResultsController 委托方法,更新应该会自动反映在 tableView 中。
https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html
- (void)controllerWillChangeContent:(NSFetchedResultsController *)controller
[self.tableView beginUpdates];
- (void)controller:(NSFetchedResultsController *)controller didChangeSection:(id <NSFetchedResultsSectionInfo>)sectionInfo
atIndex:(NSUInteger)sectionIndex forChangeType:(NSFetchedResultsChangeType)type
switch(type)
case NSFetchedResultsChangeInsert:
[self.tableView insertSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:sectionIndex]
withRowAnimation:UITableViewRowAnimationFade];
break;
- (void)controller:(NSFetchedResultsController *)controller didChangeObject:(id)anObject
atIndexPath:(NSIndexPath *)indexPath forChangeType:(NSFetchedResultsChangeType)type
newIndexPath:(NSIndexPath *)newIndexPath
UITableView *tableView = self.tableView;
switch(type)
case NSFetchedResultsChangeInsert:
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeDelete:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
case NSFetchedResultsChangeUpdate:
[self configureCell:[tableView cellForRowAtIndexPath:indexPath]
atIndexPath:indexPath];
break;
case NSFetchedResultsChangeMove:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndexPath]
withRowAnimation:UITableViewRowAnimationFade];
break;
- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller
[self.tableView endUpdates];
【讨论】:
我已经实现了这些委托,问题是它不适用于这种情况,因为我的表格视图存在作者,并且更改在 book 对象上。如果我有一个书籍表格视图,那么 UI 将立即更新,但是当书籍对象更改时,这里的委托不会在作者视图控制器上被调用。 如果你要更新 latestBook 属性,它应该被调用。请参阅我关于添加此类属性的其他答案。 您可能需要为更新添加属性 latestBookName 以触发刷新。【参考方案3】:我的解决方案:在实体Author中添加一个名为“triggerUpdate”的布尔字段,其他名称和类型也可以;如果更新作者写的书,就这样设置,
author.triggerUpdate = @(!author.triggerUpdate.boolValue);
原因是,任何更新作者的字段都会触发NSFetchedResultsChangeUpdate
类型的通知。
通过这种方式,我解决了这个问题。如果你有更好的答案,请告诉我。
【讨论】:
以上是关于核心数据 - 在对象中的多对关系更改属性后更新 UI的主要内容,如果未能解决你的问题,请参考以下文章