检测对单个 coredata 实体的更改

Posted

技术标签:

【中文标题】检测对单个 coredata 实体的更改【英文标题】:Detect changes to single coredata entity 【发布时间】:2016-11-02 00:46:31 【问题描述】:

我有以下核心数据实体:

@interface Car (CoreDataProperties)

@property (nullable, nonatomic, retain) NSSet<Part *> *parts;

@end

@interface Part (CoreDataProperties)

@property (nullable, nonatomic, retain) Car *car;

@end

这是汽车和零件之间的一对多关系。在我的一个视图控制器中,我显示了一个包含所有部件的汽车视图。我想听听汽车零件的变化。

我认为使用 KVO 会很容易。

- (void) viewWillAppear:(BOOL)animated 
    [super viewWillAppear:animated];

    [self.car addObserver:self forKeyPath:@"parts" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) context:nil];

然后:

- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
    if ([@"parts" isEqualToString:keyPath]) 
        // do what I need to do with new parts
    

但是,当我从服务器拉取更改以更新汽车零件时,即使我没有更改任何零件,也会收到对 observeValueForKeyPath 方法的意外回调。

想知道故障是否是问题所在: https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/CoreData/FaultingandUniquing.html#//apple_ref/doc/uid/TP40001075-CH18-SW7

希望使用 KVO,但也许使用 coredata 对象并不是一个好主意。我做错了什么还是应该使用替代方法?

如果我不应该使用 KVO,我相信我的其他选择是: 1. 监听 MOC 变化。这不是很好,因为我真的不知道对象发生了什么变化。 2. 在带有谓词的部件上实现 FetchedResultsController 以仅查找我感兴趣的汽车。看起来有点矫枉过正,但我​​认为这将满足我的需求。

【问题讨论】:

【参考方案1】:

NSFetchedResultsController 是观察某些数据子集变化的首选方式。

对于单个对象,您可以观察到 NSManagedObjectContext 的变化。

订阅NSManagedObjectContextObjectsDidChangeNotification

[[NSNotificationCenter defaultCenter]
    addObserver:self
       selector:@selector(contextDidChange:)
           name:NSManagedObjectContextObjectsDidChangeNotification
         object:context];

当通知到达时,处理它的userInfo

- (void)contextDidChange:(NSNotification *)notification

    NSManagedObjectContext *context = notification.object;
    NSDictionary *userInfo = notification.userInfo;

    NSArray *invalidatedAll = userInfo[NSInvalidatedAllObjectsKey];
    NSSet *invalidated      = userInfo[NSInvalidatedObjectsKey];
    NSSet *deleted          = userInfo[NSDeletedObjectsKey];
    NSSet *updated          = userInfo[NSUpdatedObjectsKey];
    NSSet *refreshed        = userInfo[NSRefreshedObjectsKey];

    // context reset
    if (invalidatedAll) 
        // probably you better have to dismiss your VC here.
        return;
    

    // invalidated
    if ([invalidated containsObject:self.car]) 
        // it make sense to dismiss here too.
        return;
    

    // deleted
    if ([deleted containsObject:self.car]) 
        // and here.
        return;
    

    // refreshed
    if ([refreshed containsObject:self.car]) 
        // update your interface.
        return;
    

    // updated
    if ([updated containsObject:self.car]) 
        // update your interface.
        return;
    

要在相关Parts 更新时接收有关Car 对象的通知,请参阅此answer。

您可以从changedValues 属性中获取更改的属性列表。

别忘了退订:

- (void)dealloc

    [[NSNotificationCenter defaultCenter]
        removeObserver:self
                  name:NSManagedObjectContextObjectsDidChangeNotification
                object:context];

更新:

这是作为UIViewController 类别实现的概念:BTDependentVC

【讨论】:

以上是关于检测对单个 coredata 实体的更改的主要内容,如果未能解决你的问题,请参考以下文章

如何参考CoreData中同一实体的单个属性更新实体的属性?

Core Data + iCloud,更改通知插入和删除关系中的对象但不更新关系中现有实体的属性

Coredata 手动迁移

Core Data 中父实体的计算属性

Core Data 更改时更新 Swiftui 视图

如何像实体框架一样在Core Data的一个类文件中对属于一个实体的方法进行分组?