Question

I have a entitiy in my NSMAnagedObject that is depended on other enititys, so after reading the documention on Depend Keys I come up with the following within my subclass

+ (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"];
}

My problem is the setter "setAssetAmount" only gets called when I change the "assetAmount" value directly, if a change the values included in the keyPathsForValuesAffectingValueForKey the setter does not get called. Am I going about this the wrong way? I expected the setter to get called each time any value changes.

Was it helpful?

Solution

If you have observers of the value of assetAmount, or bindings to the value of assetAmount, those observers and bindings would be updated appropriately when the values affecting assetAmount changed. The assetAmount getter is then invoked.

In the assetAmount getter, you can then recalculate the assetAmount that you want to return.

If you want to do the calculation every time the getter is called, you're done.

If you want to save the value of the calculation in the ivar, then you have to make sure to access the ivar directly to avoid KVO and bindings triggering. (Was a catch-22)

If you do not want the getter to be calculating the value every time, I believe you can just call assetAmount's setter from the setters for the other values. You wouldn't even need the valuesAffecting stuff, because you'd be calling the setter and triggering KVO.

In that sense, you'd need keyPathsForValuesAffectingValueForKey: only if you want your assetAmount getter to do the calculation every time. If you want it saved in the ivar, just use its setter when the other values change.

(Also, you can implement keyPathsForValuesAffectingAssetAmount if you were to go that route)

OTHER TIPS

NSArray *affectingKeys = @[@"assetAlternativeCur", @"assetAltCur", @"assetCurrency"];

tells the runtime system that these 3 other things affect the value for assetAmount... so when one of those changes you will get a notification that assetAmount changed, but your setters for the other 3 keys don't change the way that the getter for assetAmount works.. so you don't get any change...

you can force this a couple of different ways.. your assetAmount getter could be dynamic and just calculate the value then return it.

or in your setters for the other 3 keys you could do something like:

self.assetAmount = self.primativeAssetAmount;

but I would consider that sloppy and will probably cause problems down the road... you should just have one value and then another method that is the adjustedAssetAmount that has the formatted version...

an example would be temperature.

where you have a property absoluteTemp, and getters for C and F.

getter for C: => absoluteTemp+273.15

getter for F: => 9/5 * absoluteTemp + 32
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top