检测单个coredata实体的更改

时间:2016-11-02 00:46:31

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

我有以下coredata实体:

@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 个答案:

答案 0 :(得分:3)

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;
    }
}

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

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

不要忘记取消订阅:

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter]
        removeObserver:self
                  name:NSManagedObjectContextObjectsDidChangeNotification
                object:context];
}

<强>更新

这是以UIViewController类别实施的概念:
BTDependentVC