2011-11-18 65 views
2

假设我有一个名为ItemNSManagedObject子类。每当保存item实例时,我想根据瞬态属性的计算值更新属性。我知道,只要瞬态属性发生变化,我就可以更新属性,但对于这个问题,假设我不想这样做的一个很好的理由。如何在保存之前自动设置计算的NSManagedObject属性?

我试图做到这一点的方法willSave如下:

- (void)willSave 
{ 
    self.computedProperty = [self computedValueFromTransientProperty]; 
} 

保存上下文时,这会导致系统崩溃。如果我将代码移出willSave并在调用save之前显式设置该属性,则它可以正常工作。苹果文档说你应该避免更改willSave中的托管对象属性。

问题:是否有一种很好的方法可以将功能构建到NSManagedObject子类中,因此属性可以在保存之前进行更新,无需从类的外部明确设置属性,并且无需每次设置属性瞬态属性更改?

回答

7

您可以从willSave设置持久性属性,您只需要更加小心。

willSave文档:

这种方法可以有“副作用”关于持久值。例如,您可以使用 来计算来自其他瞬态或暂存器值的持久值。

如果要更新持久性属性值,则在进行更改之前,通常应测试任何新值与现有值 是否相等。如果使用标准的 访问器方法更改属性值,Core Data将观察由此产生的更改 通知,因此在保存对象的 托管对象上下文之前再次调用willSave。如果你继续在willSave中修改一个值, willSave将继续被调用,直到你的程序崩溃。

那么,发生了什么事是你改变computedProperty,这是造成willSave再次调用,从而改变其computedProperty再次呼吁willSave,直到你的程序崩溃。

要解决这个问题,你需要检查是否computedProperty需要重新设置:

- (void)willSave 
{ 
    id computed = [self computedValueFromTransientProperty]; 
    if (![self.computedProperty isEqual:computed]) 
    { 
     self.computedProperty = computed; 
    } 
} 

这将意味着computedValueFromTransientProperty将调用两次,所以你可能不希望这样做,如果该方法是计算成本很高。

另一种选择是使用原始设定的方法,这将意味着willSave将不会被调用两次,但可能会会影响依赖于你的应用程序如何与核心数据交互:

- (void)willSave 
{ 
    self.primitiveComputedProperty = [self computedValueFromTransientProperty]; 
} 
+1

谢谢,我没看到在文档中,但没有直接思考。我使用了你的第一个建议,但是为了消除双重计算,添加了一个初始化为nil并在'didSave'中设置为零的iVar。在'willSave'中,如果这个iVar是零,我将它设置为计算值。然后我使用上面的逻辑将这个iVar与持久属性进行比较。很好的工作,我只做一次昂贵的计算。谢谢! – XJones

相关问题