核心数据:发出瞬态,派生属性的KVO通知 [英] Core Data: Emitting KVO notifications for transient, derived properties

查看:107
本文介绍了核心数据:发出瞬态,派生属性的KVO通知的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有 Parent 实体具有一个具有瞬态和派生(只读)属性的自定义类 DerivedProperty



DerivedProperty 的值取决于 Parent.IndependentProperty1 ,因此每当 IndependentProperty1 更改时, DerivedProperty 的值将更改。但是 Parent Child (称为 children $ c>)和 DerivedProperty 也取决于 Parent中所有 IndependentProperty2 $


$ b / code> of Parent IndependentProperty2 c $ c>对象更改,我想通知任何观察者 DerivedProperty 也已更改。



ve到达了下面的代码。唯一的问题是没有KVO通知发出 DerivedProperty ,因为如果我尝试这样做在 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])
{
//清除缓存
_derivedProperty = nil;
}
}

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

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



我确定我需要对我的方法进行全面的反思。我试过使用KVO来观察 IndependentProperty1 IndependentProperty2 的多对多关系,但我只是不能让它工作正常。如果派生的属性不依赖于一对多的关系,那么我相信我可以使用 keyPathsForValuesAffectingValueForKey:,但是当然不会在一个 - 很多关系。



如何让KVO通知使用Core Data瞬态,派生属性依赖于一对多的关系?

$ b $首先,您正在访问您的 -objectContextDidChange中的 DerivedProperty 的ivar

方法,并短路KVO通知。



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

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

if([updatedObjects containsObject:self] || [updatedObjects intersectsSet:self.children]){
//清除缓存
[self willChangeValueForKey:@derivedProperty];
_derivedProperty = nil;
[self didChangeValueForKey:@derivedProperty];
}
}



注意



在这种情况下,OP正在使用一个瞬态属性 AND 直接访问属性的iVar。这有效地创建了两个iVars,一个由Core Data维护,另一个由OP的代码维护。这导致了碰撞。



如果您使用暂时属性,建议您将计算移动到建议的其他方法,并将访问器保留为Core Data。


I have Parent entity with a custom class that has a transient and derived (read only) property called DerivedProperty.

The value of DerivedProperty is dependent on the value of Parent.IndependentProperty1 and so whenever IndependentProperty1 changes, the value of DerivedProperty will change. However, Parent has a to-many relationship to Child (called children) and DerivedProperty is also dependent on the value of IndependentProperty2 in all of Parent's Child objects.

So whenever IndependentProperty1 of Parent or IndependentProperty2 of any of the Child objects changes, I would like to notify any observers that DerivedProperty has also changed.

I've arrived at the following code so far. The only problem is that no KVO notifications are emitted for DerivedProperty since if I try to do this in objectContextDidChange: then the code will end up in a loop.

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

I'm sure I need a total rethink on my approach here. I've tried using KVO to observe IndependentProperty1 and IndependentProperty2 of the to-many relation but I just can't seem to get it working right. If the derived property wasn't dependent on a to-many relationship then I'm sure I could just use keyPathsForValuesAffectingValueForKey: but of course that won't work across a to-many relationship.

How to I get KVO notifications working with a Core Data transient, derived property that is dependent on a to-many relationship?

解决方案

First, you are accessing the ivar for DerivedProperty in your -objectContextDidChange: method and that short circuits KVO notifications. You should really re-implement the property internally as read/write and use the generator accessor.

Second, subclasses of NSManagedObject have automatic KVO turned off by default. This is part of the architecture of Core Data. Therefore you would want to fire the notifications yourself if you are not going to use an accessor:

- (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"];
    }
}

Note

In this case the OP was using a transient property AND accessing an iVar for the property directly. This effectively created two iVars, one maintained by Core Data and another maintained by the OP's code. This was causing a collision.

If you are using a transient property it is recommended that you move calculations to another method as suggested and leave the accessors to Core Data.

这篇关于核心数据:发出瞬态,派生属性的KVO通知的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆