我开始使用瞬态属性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]
仍然返回旧的缓存值(显然是非零),因此重建当前制造商集的代码不是'我打电话给我,结果是过时的返回值。
我是否误解了缓存的瞬态属性值应该如何工作?或者我是否应该通过某种KVO回调更改行时手动取消缓存的值,以便下次访问manufacturers
时执行“if”中的更新代码?
任何帮助都非常感激。
编辑:我知道我基本上是在模拟这种瞬态属性的1:M关系(即瞬态关系,因为缺少更好的词) ,我也知道documentation警告不要将setPrimitiveValue:forKey:
用于关系:
您通常应该使用此方法 只修改属性(通常 瞬态),而不是关系。如果你 尝试设置与a的多对多关系 新的NSMutableSet对象,它会 (最终)失败了。在不寻常的 您需要修改的事件 使用这种方法的关系,你 首先使用现有的集合 primitiveValueForKey :(确保 方法不返回nil),创建一个 可变副本,然后修改副本
但是,由于我没有在真实的 1:M关系上设置原始值,只有我模拟的瞬态值,我假设此警告不适用于我的用例。
编辑#2:因为我只想跟踪在lines
集中添加或删除对象的时间(这是manufacturers
预期值的唯一方法可以改变),而不是试图跟踪已经在lines
集合中的对象的属性更新,我认为我不应该像这样重量级的任何东西:https://github.com/mbrugger/CoreDataDependentProperties
解决方案:根据以下答案,我实施了以下解决方案,以便在manufacturers
更新时删除lines
设置。任何人都可以看到任何问题,或建议任何更有效的方法来实现它?重要的是,此操作要快,因为它是在主线程中完成的,并且会明显延迟在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];
}
}
答案 0 :(得分:1)
keyPathsForValuesAffectingManufacturers并不意味着在更改线路时将删除制造商的价值,这意味着当线路发生变化时应通知观察制造商的对象,因为更改线路会自动更改制造商而不会触发通知。当一个属性基于另一个属性获取其值时使用。根据您的情况,您需要在更换生产线时更换制造商。