【发布时间】:2011-06-02 11:30:53
【问题描述】:
我开始使用瞬态属性a little while ago,并认为我对它们非常了解,但是这个行为并没有我想象的那样。它在数据模型中被定义为具有未定义类型的瞬态属性,因此被声明为属性:
@property (nonatomic, readonly) NSSet * manufacturers;
该属性被声明为依赖于该对象上的另一个 1:M 关系:
+ (NSSet *) keyPathsForValuesAffectingManufacturers
{
return [NSSet setWithObject:@"lines"];
}
我已经为这个瞬态属性实现了一个相当标准的 getter:
- (NSSet *) manufacturers
{
[self willAccessValueForKey:@"manufacturers"];
NSSet *mfrs = [self primitiveManufacturers];
[self didAccessValueForKey:@"manufacturers"];
if (mfrs == nil)
{
NSMutableSet *working = [NSMutableSet set];
/* rebuild the set of manufacturers into 'working' here */
mfrs = working;
[self setPrimitiveManufacturers:mfrs];
}
return mfrs;
}
不工作的部分是manufacturers 的缓存原始值似乎不会在对象被添加/从该对象的lines 关系中删除时被清除。 manufacturers 访问器在添加/删除行时肯定会被调用,但[self primitiveManufacturers] 仍然返回旧的缓存值(这显然不是 nil),因此不会调用重建当前制造商集的代码,我最终得到一个过时的返回值。
我是否误解了缓存的瞬态属性值应该如何工作?还是我应该在通过某种 KVO 回调更改行时手动取消缓存值,以便在下次访问 manufacturers 时执行“if”中的更新代码?
非常感谢任何帮助。
编辑:我知道我基本上是在模拟与此瞬态属性的 1:M 关系(即 瞬态关系,因为需要更好的词) ,而且我也知道documentation 警告不要使用setPrimitiveValue:forKey: 来建立关系:
您通常应该使用此方法 只修改属性(通常 瞬态),而不是关系。如果你 尝试将一对多关系设置为 新的 NSMutableSet 对象,它将 (最终)失败。在不寻常的 您需要修改的事件 使用这种方法的关系,你 首先使用现有的集合 PrimitiveValueForKey:(确保 方法不返回 nil),创建一个 可变副本,然后修改副本
但是,由于我没有在 真实 1:M 关系上设置原始值,只是我的模拟瞬态关系,我假设此警告不适用于我的用例。 p>
编辑#2:因为我只是想跟踪何时从lines 集合中添加或删除对象(这是manufacturers 的预期值可以更改的唯一方法),与尝试跟踪对已在 lines 集合中的对象的属性的更新相反,我认为我不需要像这样重量级的东西:https://github.com/mbrugger/CoreDataDependentProperties
解决方案:根据下面的答案,我实施了以下解决方案,以在更新lines 时清除manufacturers 集。任何人都可以看到这方面的任何问题,或者提出任何更有效的实施方式吗?重要的是,此操作要快,因为它是在主线程中完成的,并且会明显延迟与 line 更新同时发生的 UI 更新。
- (void) awakeFromFetch
{
[super awakeFromFetch];
[self addObserver:self forKeyPath:@"lines" options:0 context:nil];
}
- (void) awakeFromInsert
{
[super awakeFromInsert];
[self addObserver:self forKeyPath:@"lines" options:0 context:nil];
}
- (void) didTurnIntoFault
{
[self removeObserver:self forKeyPath:@"lines"];
[super didTurnIntoFault];
}
- (void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
if ([object isEqual:self] && [keyPath isEqualToString:@"lines"])
{
[self setPrimitiveManufacturer:nil];
}
else
{
[super observeValueForKeyPath:keyPath
ofObject:object
change:change
context:context];
}
}
【问题讨论】:
标签: iphone core-data nsmanagedobject transient