【问题标题】:Detect changes to single coredata entity检测对单个 coredata 实体的更改
【发布时间】: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 以仅查找我感兴趣的汽车。看起来有点矫枉过正,但我​​认为这将满足我的需求。

【问题讨论】:

    标签: ios core-data nsfetchedresultscontroller key-value-observing


    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 1970-01-01
      • 2014-12-31
      • 1970-01-01
      • 1970-01-01
      • 2013-07-14
      相关资源
      最近更新 更多