NSManagedObject 子类中的自定义设置器

Posted

技术标签:

【中文标题】NSManagedObject 子类中的自定义设置器【英文标题】:Custom Setter in NSManagedObject Subclass 【发布时间】:2014-03-24 17:26:29 【问题描述】:

我的 NSManagedObject 中有一个依赖于其他实体的实体,因此在阅读了 Depend Keys 上的文档后,我在我的子类中提出了以下内容

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key

    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];

    if ([key isEqualToString:@"assetAmount"]) 
        NSArray *affectingKeys = @[@"assetAlternativeCur", @"assetAltCur", @"assetCurrency"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    
    return keyPaths;



- (void)setAssetAmount:(NSDecimalNumber *)assetAmount

    [self willChangeValueForKey:@"assetAmount"];

    if ([[self useAlternativeCur] boolValue] == YES) 
        NSDecimalNumber *result;
        result = [[self assetConversionRate] decimalNumberByMultiplyingBy:[self assetAlternativeCur]];
        [self setPrimitiveAssetAmount:result];
     else 
        [self setPrimitiveAssetAmount:assetAmount];
    
    [self didChangeValueForKey:@"assetAmount"];

我的问题是设置器“setAssetAmount”只有在我直接更改“assetAmount”值时才会被调用,如果更改 keyPathsForValuesAffectingValueForKey 中包含的值,则设置器不会被调用。我会以错误的方式解决这个问题吗?我希望设置器在每次任何值更改时都会被调用。

【问题讨论】:

【参考方案1】:

如果您有assetAmount 值的观察者,或对assetAmount 值的绑定,那么当影响assetAmount 的值发生变化时,这些观察者和绑定会相应地更新。然后调用assetAmount getter

在assetAmount getter中,你可以重新计算你想要返回的assetAmount。

如果您想在每次调用 getter 时都进行计算,那么您就完成了。

如果你想将计算的值保存在 ivar 中,那么你必须确保直接访问 ivar 以避免触发 KVO 和绑定。(是一个 catch-22)

如果您不希望 getter 每次都计算值,我相信您可以从 setter 中调用assetAmount 的 setter 来获取其他值。你甚至不需要 valuesAffecting 的东西,因为你会调用 setter 并触发 KVO。

从这个意义上说,如果您希望您的assetAmount getter 每次都进行计算,则需要 keyPathsForValuesAffectingValueForKey: 。如果您希望将其保存在 ivar 中,只需在其他值更改时使用它的 setter。

(另外,如果你要走那条路,你可以实现 keyPathsForValuesAffectingAssetAmount)

【讨论】:

我确实使用了绑定,就像您指出的那样,当其他值发生变化时,将调用assetAmount getter。此外,我让 getter 执行必要的计算并返回一个新值。但我对你将如何实现最后一段感到困惑......我将如何保存 getter 返回的这个新值? 据我所知,您可以使用primitiveValue 的东西——这是获取具有核心数据的ivars 的方法。但现在我想得更多,这是一个第 22 条规则,没有复杂的事情,你必须做新的计算才能知道你是否必须做新的计算。另一种方法是让影响assetAmount 的其他三个值的setter 发出willChangeValueForKeyassetAmount 并为assetAmount 设置新的原始值,然后调用didChangeValueForKeyassetAmount,并触发对自动合成的getter 的调用。我将编辑我的答案。【参考方案2】:
NSArray *affectingKeys = @[@"assetAlternativeCur", @"assetAltCur", @"assetCurrency"];

告诉运行时系统这 3 个其他因素会影响 assetAmount 的值...因此,当其中一个更改时,您将收到 assetAmount 更改的通知,但其他 3 个键的设置器不会改变 assetAmount 的 getter 的工作方式.. 所以你不会得到任何改变......

您可以通过几种不同的方式强制执行此操作。您的 assetAmount getter 可以是动态的,只需计算值然后返回即可。

或者在其他 3 个键的设置器中,您可以执行以下操作:

self.assetAmount = self.primativeAssetAmount;

但我认为这很草率,并且可能会导致问题...您应该只有一个值,然后是另一种方法,即具有格式化版本的 adjustedAssetAmount...

一个例子是温度。

你有一个property absoluteTemp,以及 C 和 F 的 getter。

getter for C: => absoluteTemp+273.15

getter for F: => 9/5 * absoluteTemp + 32

【讨论】:

以上是关于NSManagedObject 子类中的自定义设置器的主要内容,如果未能解决你的问题,请参考以下文章

NSManagedObject 子类的自定义初始化

类别中的自定义 NSManagedObject 设置器

NSManagedObject 验证和子类

Swift:CoreData NSManagedObject 的自定义设置器

带有循环的 NSManagedObject 子类的深拷贝

Swift 中的 NSManagedObject 子类不能使用自定义访问器?