ios - 核心数据 : Emitting KVO notifications for transient, 派生属性

标签 ios cocoa-touch core-data key-value-observing

我有一个带有自定义类的 Parent 实体,该类具有名为 DerivedProperty 的 transient 派生(只读)属性。

DerivedProperty 的值取决于 Parent.IndependentProperty1 的值,因此每当 IndependentProperty1 发生更改时,DerivedProperty 的值 将会改变。但是,ParentChild 具有一对多关系(称为 children),并且 DerivedProperty 也依赖于所有 ParentChild 对象中 IndependentProperty2 的值。

因此,每当 ParentIndependentProperty1 或任何 Child 对象的 IndependentProperty2 发生变化时,我想通知所有观察者 DerivedProperty 也已更改。

到目前为止我已经得到了以下代码。唯一的问题是 DerivedProperty 不会发出 KVO 通知,因为如果我尝试在 objectContextDidChange: 中执行此操作,那么代码将最终陷入循环。

- (void) awakeFromInsert
{
    [super awakeFromInsert];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(objectContextDidChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:self.managedObjectContext];
}


- (void) awakeFromFetch
{
    [super awakeFromFetch];

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(objectContextDidChange:) name:NSManagedObjectContextObjectsDidChangeNotification object:self.managedObjectContext];
}

- (void) objectContextDidChange: (NSNotification *) notification
{
    NSSet *updatedObjects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];

    if ([updatedObjects containsObject:self] || [updatedObjects intersectsSet:self.children])
    {
        //clear caches
        _derivedProperty  = nil;
    }
}

- (void) didTurnIntoFault
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (NSString *) DerivedProperty
{
    if (_derivedProperty == nil)
    {
        _derivedProperty  = [self someExpensiveCalculation];
    }
    return _derivedProperty  ;
}

我确信我需要彻底重新思考我的方法。我尝试使用 KVO 来观察对多关系的 IndependentProperty1IndependentProperty2 ,但我似乎无法让它正常工作。如果派生属性不依赖于一对多关系,那么我确信我可以只使用 keyPathsForValuesAffectingValueForKey: 但当然这不适用于一对多关系。

如何获取与依赖于一对多关系的核心数据 transient 派生属性一起使用的 KVO 通知?

最佳答案

首先,您将在 -objectContextDidChange: 方法中访问 DerivedProperty 的 ivar,并短路 KVO 通知。您确实应该在内部将属性重新实现为读/写并使用生成器访问器。

其次,NSManagedObject 的子类默认关闭自动 KVO。这是核心数据架构的一部分。因此,如果您不打算使用访问器,您可能需要自己触发通知:

- (void) objectContextDidChange: (NSNotification *) notification
{
    NSSet *updatedObjects = [[notification userInfo] objectForKey:NSUpdatedObjectsKey];

    if ([updatedObjects containsObject:self] || [updatedObjects intersectsSet:self.children]) {
        //clear caches
        [self willChangeValueForKey:@"derivedProperty"];
        _derivedProperty  = nil;
        [self didChangeValueForKey:@"derivedProperty"];
    }
}

注意

在本例中,OP 使用 transient 属性并且直接访问该属性的 iVar。这有效地创建了两个 iVar,一个由 Core Data 维护,另一个由 OP 代码维护。这导致了碰撞。

如果您使用 transient 属性,建议您按照建议将计算移至其他方法,并将访问器保留为 Core Data。

关于ios - 核心数据 : Emitting KVO notifications for transient, 派生属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16738126/

相关文章:

javascript - 错误 : Invariant Violation: Touchable child must either be native or forward setNativeProps to a native component stack

ios - 根据内容调整 UILabel 的大小

ios - anchor 偏移不适用于此处 map map 叠加 (iOS Swift)

iphone - MPMediaPickerController - 选择整个专辑

iphone - MainWindow.xib 和 iPhone 5(4 英寸显示屏)

ios - SIGTRAP(TRAP_BRKPT) CollectionView cellForItemAt IndexPath 中崩溃

ios - Nsdateformatter + 时区问题

ios - 核心数据迁移 - 如何填充一个新对象?

iphone - iOS:在 iCloud 中备份核心数据数据库?

ios - NSManagedObjectContext:如何从 UIViewController 获取 iOS 中的 ManagedObjectContext?