当子关系实体在核心数据中更改时通知父实体

时间:2011-10-11 18:26:16

标签: ios core-data entity-relationship

当父实体中的任何一个关系对象发生变化时,是否可以在父实体中接收回调或通知?当实体的属性发生变化时,这很有用。以下方法......

- (void)didChangeValueForKey:(NSString *)key

在我的Entity子类上调用

。但是,当其中一个关系中的属性发生更改时,不会调用此方法。

我要做的是当我的父实体中的任何一个属性或关系对象发生更改时,更新timeStamp属性。

2 个答案:

答案 0 :(得分:5)

父实体可以将自己设置为关系的观察者,并在关系发生变化时收到通知。但是,只有在实际关系(添加或删除子项)发生时才会触发。

观察特定的儿童实体要复杂得多。有几种方法可以解决这个问题:

  1. 让孩子在其属性发生变化时ping父母。
  2. 让家长听取NSManagedObjectContextDidSaveNotification并查看其中的任何一个孩子是否在保存
  3. 让父母观察孩子的价值观。
  4. 可能还有其他解决方案,但我推荐#2。设置非常简单,性能影响非常小。

答案 1 :(得分:1)

在另一个答案中,我发现1,2和3效率太低。特别是2和“看着它的孩子的父母”博客文章中的例子。我的问题是每个父母都必须回应上下文通知,基本上每个对象都被保存(如果它是孩子)(更不用说在这种情况下ContextDidSave更合适!)。相反,我会提出一个选项4:

  1. 让子项覆盖didSave并广播包含父级的NSManagedObjectContextDidSaveNotification。
  2. 我的解决方案效率更高,感觉更加面向对象,因为正在变化的对象正在响应自己的变化。要实现这一点,请在子对象中使用:

    -(void)didSave{
        [super didSave];
        // notify that the parent has changed.
        [[NSNotificationCenter defaultCenter] postNotificationName:NSManagedObjectContextObjectsDidChangeNotification
                                                            object:self.managedObjectContext
                                                          userInfo:@{NSUpdatedObjectsKey : [NSSet setWithObject:self.parent]}];;
    }
    

    要更新父时间戳,我一直在使用的以下简洁解决方案(second last post)可能有所帮助,例如:在父使用中:

    - (void) awakeFromInsert
    {
        [super awakeFromInsert];
        // set the default dates
        NSDate* date = [NSDate date];
        self.timestamp = date;
        //allow any future modifications to change the timestamp
        _finishedStartup = YES;
    }
    
    - (void) awakeFromFetch
    {
        [super awakeFromFetch];
        // we should already have creation and modified dates.
        _finishedStartup = YES;
    }
    
    - (void) didChangeValueForKey: (NSString *) thisKey
    {
        [super didChangeValueForKey: thisKey];
    
        if(![thisKey isEqualToString:@"timestamp"] && // prevent infinite loop
           ![self isFault] &&
           ![[[self managedObjectContext] undoManager] isUndoing] &&
           _finishedStartup) // ensures we arent being called by the object being loaded from fetched data.
        {
            self.timestamp = [NSDate date];
        }
    }