Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implement own setter or use KVO?

In short, when the property value changing, I have to update some logic in my code, for example:

- (void)setProp:(NSString *)theProp
{
  if (prop != theProp){
    [prop release];
    prop = [theProp copy];
    [self myLogic];
  }
}

or:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
  if ([keyPath isEqualToString:@"prop"]){
    [self myLogic];
  }  
}

Which is the best way, and WHY?

EDIT: I prefect the second way, because I don't know what the compiler will generate @synthesize directive for me, I choose to believe the compiler is more smarter than my owe setter implementation, hence I will not break something.

like image 999
cxa Avatar asked May 05 '11 06:05

cxa


2 Answers

The first snippet is the way to go, if you’re interested in changes in the same object. You only need to use the second if you are interested in changes to other objects, using it to observe self is overkill.

like image 125
Sven Avatar answered Sep 20 '22 15:09

Sven


Tough call, IMHO both options suck.

The first one forces you to write your own setter, which is a lot of boilerplate code. (Not to mention that you have to remember to also fire KVO notifications with willChangeValueForKey: and didChangeValueForKey: if you want KVO for the property in question to work.)

The second option is also quite heavy-weight and your implementation is not enough. What if your superclass also has some KVO in place? You’d have to call super somewhere in the handler. If not, are you sure your superclass won’t change? (More about KVO in a related question.)

Sometimes you can sidestep the issue using other methods like bindings (if you’re on a Mac) or plain notifications (you can post a notification that a model changed and all interested parties should refresh).

If you have many recalculations like this and can’t find any better way around, I would try to write a superclass with better observing support, with interface like this:

[self addTriggerForKeyPath:@"foo" action:^{
    NSLog(@"Foo changed.");
}];

This will take more work, but it will keep your classes cleanly separated and you can solve all KVO-related problems on one place. If there are not enough recalculated properties to make this worthwile, I usually go with the first solution (custom setter).

like image 29
zoul Avatar answered Sep 17 '22 15:09

zoul