如何在CoreData中侦听特定实体保存/更新

时间:2014-12-30 15:25:55

标签: ios objective-c core-data magicalrecord

我尝试的第一件事是使用FetchedResultsController来解决我的问题。这是FRC的非典型用法,因为我没有更新TableView,我只是用它来确定实体是否在改变,所以我知道何时保存到服务器:

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从nil变为非nil,我将看不到更新,因为FRC仅侦听Document实体上的更改。此处列出的限制:http://www.mlsite.net/blog/?p=825和此处Changing a managed object property doesn't trigger NSFetchedResultsController to update the table view

我不确定是否真的想要实施这种解决方法,因为我使用FRC来解决它不应该做的事情。我不认为苹果会修复这个限制,所以我真的不想将一个圆形钉子撞到一个方孔来解决我的问题。

几个选项

保存实体后在代码中触发通知,然后在其他地方侦听。我唯一不喜欢的就是程序员要做到这一点并保持最新,即如果有人出现并将实体保存在另一个地方,他们必须记得发出通​​知。

OR

侦听保存到默认的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中?

如果答案是否定的,是否有一个很好的选择来听取特定实体(及其关系)的变化?

2 个答案:

答案 0 :(得分:10)

没有办法听取对特定实体集的更改;捕获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
        }
    });
}

答案 1 :(得分:2)

在阅读了文档和其他一些表格之后,我还提出了另一种可能的解决方案。

为什么不覆盖托管对象的 - (void)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上保存的内容。即使我可以在后台任务中进行过滤,但在这种情况下,我仍然需要过滤大量数据,而我无需处理。

思想?