如何在CoreData中侦听特定的实体保存/更新
我尝试的第一件事是使用FetchedResultsController来解决我的问题。这是一个非典型的使用FRC的,我没有更新的TableView,我用它只是为了确定是否实体正在发生变化,所以我知道什么时候保存到服务器:如何在CoreData中侦听特定的实体保存/更新
self.fetchedResultsController = [Document MR_fetchAllSortedBy:@"timestamp"
ascending:NO
withPredicate:[NSPredicate predicateWithFormat:@"report.remoteId != nil && dirty == YES"]
groupBy:nil
delegate:self
inContext:_managedObjectContext];
这里的问题是,FRC在关系实体更改时不会收到更新。 IE如果report.remoteId从零变为非零我不会看到更新,因为FRC仅监听文档实体上的更改。这里列出的限制:http://www.mlsite.net/blog/?p=825和这里Changing a managed object property doesn't trigger NSFetchedResultsController to update the table view
不知道我真的想实施解决方法,因为我倒下了,就像我使用FRC的东西,它不是为了做的事情。我不认为苹果会解决这个限制,所以我并不是真的想把一个圆形钉子打成方形洞来解决我的问题。
几个选项
消防代码的通知后,我已保存的实体,然后听一听是其他地方。唯一我不喜欢的事情是,程序员要做到这一点并保持最新状态,也就是说,如果有人出现并将实体保存在另一个地方,他们必须记得发出通知。
或
侦听保存到默认MOC。这是我真正想做的事情。类似这样的:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(handleDataModelChange:)
name:NSManagedObjectContextObjectsDidChangeNotification
object:[NSManagedObjectContext MR_defaultContext]];
- (void)handleDataModelChange:(NSNotification *)note {
NSSet *updatedObjects = [[note userInfo] objectForKey:NSUpdatedObjectsKey];
NSSet *deletedObjects = [[note userInfo] objectForKey:NSDeletedObjectsKey];
NSSet *insertedObjects = [[note userInfo] objectForKey:NSInsertedObjectsKey];
// Do something in response to this
}
这是我的两难。这将监听默认MOC上的所有更改。我真的只关心一些实体的变化。所以是的,我可以在每次通话中筛选出我关心的实体。但是,我有一个案例,我拯救了大量我不关心的其他实体。这意味着NSManagedObjectContextObjectsDidChangeNotification会触发很多时间,大部分时间我都不在乎。我不想通过不断收到此通知并花时间筛选出我不关心的所有实体来减慢我的应用程序速度。
有没有办法监听特定的实体保存?无论是在CoreData,还是MagicalRecord?
如果答案是否定的,是有听更改特定实体(及其关系)一个很好的选择?
有没有办法听的变化一组特定的实体;捕捉NSManagedObjectContextObjectsDidChangeNotification
(或已经或将要保存)并且过滤是正确的方法,但要注意的是,如果您正在讨论实体的特定实例,则键值观察也是一种选择。
但是,值得注意的是NSManagedObjectID
是线程安全的并为NSEntityDescription
提供了一个getter。所以你可以
- (void)handleDataModelChange:(NSNotification *)note {
NSSet *updatedObjects = [[note userInfo] objectForKey:NSUpdatedObjectsKey];
NSSet *deletedObjects = [[note userInfo] objectForKey:NSDeletedObjectsKey];
NSSet *insertedObjects = [[note userInfo] objectForKey:NSInsertedObjectsKey];
NSMutableArray *objectIDs = [NSMutableArray array];
[objectIDs addObjectsFromArray:[updatedObjects.allObjects valueForKey:@"objectID"]];
[objectIDs addObjectsFromArray:[deletedObjects.allObjects valueForKey:@"objectID"]];
[objectIDs addObjectsFromArray:[insertedObjects.allObjects valueForKey:@"objectID"]];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(){
NSSet *affectedEntities = [NSSet setWithArray:[objectIDs valueForKeyPath:@"entity.name"]];
if([affectedEntities containsObject:@"InterestingEntity"]) {
// get back onto the main thread and do some proper work;
// possibly having collated the relevant object IDs here
// first — whatever is appropriate
}
});
}
通过阅读文档和其他一些形式后,我也想出了另一种可能的解决方案。
为什么不覆盖 - (无效)didSave管理对象的方法,以捕获对象上的变化。
@implementation Report (helper)
- (void) didSave {
[super didSave];
// if not on default context no-op
if ([NSManagedObjectContext MR_defaultContext] != self.managedObjectContext) return;
// send custom notification here
}
@end
与发送自定义通知还是交易,但在管理对象至少在封装,使得开发者不必担心在哪里发送通知。
从好的一面来看,这只对我关心的被管理对象执行。
减号是它被调用所有托管对象上下文。不过,我不认为MOC支票会是一个沉重的打击者。
不知道这是否比在默认MOC上进行保存和过滤时收听更好/更差。此外,在这种情况下,我知道我只在该MOC上收听节目。尽管我可以过滤后台任务,但我仍然在过滤大量的数据,这种情况下我不需要处理。
想法?
注册到'NSManagedObjectContextDidSaveNotification'。 –
谢谢@Tommy!比覆盖NSManagedObject的onSave方法更好/更糟? – lostintranslation
取决于您的使用情况。如果您试图捕获实体Q的所有实例的保存,并且您一次保存1000个实例(可能来自Web服务或某处),那么您将只获得一个通知,但只有1,000个'didSave'。我想问题在于你是否希望让这些对象独立行事(例如,应用自动更正验证),或者你正在以某人的角度来看待这些对象(例如,你有一个大而复杂的视图可以做一些事情基于数据的总体而不是仅显示每个数据)。 – Tommy
......我可能唯一难以理解的是,在表格视图这样的关键值观察中,由于添加和删除观察者的成本而快速滚动时会产生意想不到的成本,大概是因为从0观察者到1和副作用反之亦然是一种调整方法,突变消息传递图和某种内部到KVO实例图。在这种情况下,我发现捕获通知,处理和推送主队列变化的阻塞列表是一个更好的解决方案。 – Tommy