when to use “willChangeValueForKey” and “didChangeValueForKey”?

前端 未结 8 807
我在风中等你
我在风中等你 2021-01-30 10:53

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

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


        
相关标签:
8条回答
  • 2021-01-30 11:32

    Those have to do with manually controlling key value observing. Normally the system takes care of it but these allow you some control. Look at this documentation to understand when and how to use them here.

    0 讨论(0)
  • 2021-01-30 11:33

    Be really careful when overriding didChangeValueForKey:. The best thing is not to do it at all. But if you do, make sure you call super, otherwise you will have a memory leak as demonstrated here: https://github.com/jfahrenkrug/KVOMemoryLeak

    0 讨论(0)
  • 2021-01-30 11:37

    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.

    0 讨论(0)
  • 2021-01-30 11:44

    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.

    0 讨论(0)
  • 2021-01-30 11:44
    • If you want to do stuff just before the value gets changed, use willChangeValueForKey.
    • If you want to do stuff just after the value gets changed, use didChangeValueForKey.

    Edit: ignore me, was reading too fast - Barry is right :-)

    0 讨论(0)
  • 2021-01-30 11:44

    if you rewrite property getter methods, please use it.

    @property (assign, nonatomic, getter=isLogined) BOOL logined;
    
    0 讨论(0)
提交回复
热议问题