0

Not sure my title best describes my question but couldn't think of a better one!

I have 2 Managed Objects, 'Transaction' and 'Split'. Transaction has a 1 to many relationship with 'Split' and therefore has an NSSet of Split Objects. Split has 2 properties, Category (NSString) and Amount (NSDecimalNumber).

A Transaction has a value which I currently calcluate by iterating through the NSSet of Split objects adding up all the 'Amount' properties.

This is working fine and I don't seem to have any performance issues but I suspect this wont scale well when you have 1000's of transactions.

What I think I need to do, is have an 'Amount' property on the Transaction object (as a cahce) and update this everytime and change is made to the 'Amount' property of one of its 'Split' objects contained within its NSSet.

Hope I'm making sense so far..

My question is the best way of achieving this? It feels like something KVO was designed to do but I haven't really used this before. Does my Transaction object need to be notified when the 'Amount' value of one of its Splits changes and can therefore recalculate its own value?

Or should this be done in the setter for the Amount property in the Split??

Sure this is a common problem and one for which a very elegant solution exists? Any advice and sample code very much appreciated..?

Cheers

Aaron Brager
  • 65,323
  • 19
  • 161
  • 287

1 Answers1

0

I would go with overriding the amount setter of Split.
This way, if you some day need to optimise, or scale-up, you could change the one-to-many relationship, to a relationship with no inverse, saving the creation of the set entirely (deletion enforcement in case of removing the inverse will be more complex).

code will look something like:

//not tested
- (void) setAmount:(NSUInteger)amount
{
    [self willChangeValueForKey:@"amount"];
    [self setPrimitiveValue:@(amount) forKey:@"amount"];
    self.transaction.amount += amount;
    [self didChangeValueForKey:@"amount"];
}

Edit (@Tommy):

On deletion you will need to subtract the Split amout:

- (void) prepareForDeletion
{
    self.transaction.amount -= self.amount;
}

Also, be very careful with setting your context merge policy, so changes to a transaction from different contexts will not overwrite each other (use the default error policy).

Dan Shelly
  • 5,991
  • 2
  • 22
  • 26