如何在保存之前自动设置计算的NSManagedObject属性?

XJo*_*nes 2 core-data nsmanagedobject ios

假设我有一个NSManagedObject名为的子类Item.每当item保存实例时,我想根据瞬态属性中的计算值更新属性.我知道只要瞬态属性发生变化,我就可以更新属性,但是对于这个问题,假设有一个很好的理由我不想这样做.

我尝试在willSave方法中执行以下操作:

- (void)willSave
{
    self.computedProperty = [self computedValueFromTransientProperty];
}
Run Code Online (Sandbox Code Playgroud)

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

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

She*_* Lo 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这意味着computedValueFromTransientProperty将被调用两次,因此如果方法计算成本昂贵,您可能不希望这样做.

另一种选择是使用原始set方法,这意味着willSave不会被调用两次,但可能会产生副作用,具体取决于您的应用与Core Data的交互方式:

- (void)willSave
{
    self.primitiveComputedProperty = [self computedValueFromTransientProperty];
}
Run Code Online (Sandbox Code Playgroud)