即使定义了相关键,我是否还必须手动更新瞬态属性?

时间:2011-01-02 12:40:32

标签: iphone core-data nsmanagedobject transient

我开始使用瞬态属性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];
    }
}

1 个答案:

答案 0 :(得分:1)

keyPathsForValuesAffectingManufacturers并不意味着在更改线路时将删除制造商的价值,这意味着当线路发生变化时应通知观察制造商的对象,因为更改线路会自动更改制造商而不会触发通知。当一个属性基于另一个属性获取其值时使用。根据您的情况,您需要在更换生产线时更换制造商。