核心数据:发出瞬态,派生属性的KVO通知 [英] Core Data: Emitting KVO notifications for transient, derived properties
问题描述
我有 Parent
实体具有一个具有瞬态和派生(只读)属性的自定义类 DerivedProperty
。
DerivedProperty
的值取决于 Parent.IndependentProperty1
,因此每当
IndependentProperty1
更改时, DerivedProperty
的值将更改。但是 Parent
与 Child
(称为 children $ c> $ 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 $
- (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屋!