4

不久前我开始使用瞬态属性,并认为我对它们非常了解,但是这个并没有像我想象的那样表现。它在数据模型中被定义为具有未定义类型的瞬态属性,因此被声明为属性:

@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 关系(即瞬态关系,因为需要更好的词),而且我也知道文档警告不要使用setPrimitiveValue:forKey:for 关系:

您通常应该只使用此方法来修改属性(通常是瞬态的),而不是关系。如果您尝试为新的 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];
    }
}
4

1 回答 1

1

keyPathsForValuesAffectingManufacturers 并不是说​​换行时会删除制造商的值,而是说换行时应该通知观察制造商的对象,因为换行会自动更改制造商,而不会触发通知。当一个属性基于另一个属性获取其值时使用此选项。针对你的情况,换线的时候需要换厂家。

于 2011-01-04T01:59:14.460 回答