Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

when to use "willChangeValueForKey" and "didChangeValueForKey"?

I saw these lines in a demo project, but I couldn't understand why it did that.

[self willChangeValueForKey:@"names"]; [self didChangeValueForKey:@"names"]; 

It called didChangeValueForKey immediately after willChangeeValueForKey. Does it make any sense?

Furthermore, when should be the right time to call this two methods? Thanks a lot!! :)

like image 494
Frost Avatar asked Jun 10 '10 20:06

Frost


2 Answers

This is, in fact, an anti-pattern. You should not call -willChangeValueForKey: followed by -didChangeValueForKey: without any intervening actual property change. In some cases, doing so can mask KVO problems elsewhere in your code and force observers to update their state related to the property in question. Ultimately, however, you (or the author of the example you cite) should fix the rest of the code so that this anti-pattern is unnecessary.

The correct usage of -will|didChangeValueForKey: is when you are modifying a property without using KVC-compliant accessors/setters such that the KVO mechanism would not notice the change. For a contrived example, consider modifying the backing instance variable for an attribute directly:

@interface Foo {    int bar; } @end  @implementation Foo - (void)someMethod {   bar = 10; } @end 

KVO observers that had registered for notification of changes in the bar property would not recieve notification of the change to bar in -someMethod. To make the KVO machinery work, you could modify -someMethod:

- (void)someMethod {   [self willChangeValueForKey:@"bar"];   bar = 10;   [self didChangeValueForKey:@"bar"]; } 

Of course, it would be better to use a @property declaration and to use KVC-compliant accessors/setters (either manually coded or @synthesized), but this is a contrived example.

like image 186
Barry Wark Avatar answered Oct 10 '22 18:10

Barry Wark


KVO will operate correctly with custom setters for properties; this has always been the case for NSObject-derived classes. The runtime machinery looks for an invocation of the relevant setter method, and implicitly calls "willChangeValueForKey" prior to executing the setter, then implicitly calls "didChangeValueForKey" after the setter completes.

You can disable this automatic behavior if you wish to have more fine-grained control over KVO notifications. As mentioned above, readonly properties whose value you change by modifying the backing ivar, or whose values are derived by calculation, are places where you would use the manual notifications (although there is a mechanism, keyPathsAffectingValueFor, where you can tell the runtime that the value of a property is dependent on the change of another property, and it will send the change notification as appropriate.) To disable the automatic behavior on a per-property basis, you put in a class method + (BOOL) automaticallyNotifiesObserversOf and return NO.

I often disable automatic KVO notifications, because I have found that a KVO notification is generated when invoking a setter, even if the value of the property is being set to the same as its current value (e.g. no change). I wish to suppress the pointless notification for efficiency's sake:

+ (BOOL)automaticallyNotifiesObserversOfMyProperty {   return NO; }  - (void)setMyProperty:(NSInteger)myProperty {   if(_myProperty != myProperty)   {     [self willChangeValueForKey:@"myProperty"];     _myProperty = myProperty;     [self didChangeValueForKey:@"myProperty"];   } } 

A good discussion can be found in the NSKeyValueObserving.h header, that you can navigate to by CMD+clicking on the method names "willChangeValueForKey" and "didChangeValueForKey" in XCode.

like image 38
Kevin Draz Avatar answered Oct 10 '22 18:10

Kevin Draz