KVO & KVC

KVOUsage and underlying principles

  • Usage: Add observer, then how to implement listening proxy
  • KVOThe bottom layer usesisa-swizlingThe technology.
  • OCFor each object/class inisaA pointer,isaRepresents the object of which class this object is.
  • When an observer is registered for an object property, the system creates a new intermediate class (intermediate class) inherit the originalclass, put the object’sisaThe pointer points to the middle class.
  • And then the middle class will be rewrittensetterMethod, callsetterBefore the callwillChangeValueForKey, the callsetterAfter the calldidChangeValueForKeyTo notify all observers that the value has changed.
  • Rewrite the-classMethod, trying to trick us into thinking that this class is the same as it was.

Advantages and disadvantages of KVO

advantages

  • 1. It can quickly and conveniently realize the association synchronization of two objects, for exampleview & model
  • 2. Can observe the change of the new value and the old value
  • 3. Data changes of nested types can be easily observed

disadvantages

  • 1. The observed object passesstringType Settings, if written errors or variable names change, can be passed at compile time but occur at run timecrash
  • 2. Observing multiple values requires multiple values in the proxy methodifjudge
  • 3. Forgetting to remove an observer or repeatedly removing an observer can causecrash

How to trigger it manuallyKVO

  • KVOThe mechanism is throughwillChangeValueForKey:anddidChangeValueForKey:Triggered by two methods.
  • Called before observing object changeswillChangeValueForKey:
  • Called after observing object changesdidChangeValueForKey:
  • So you only need to call it manually before and after changing the observation value.

Add filter criteria to KVO

  • rewriteautomaticallyNotifiesObserversForKey, need to be screenedkeyreturnNO.
  • setterAdd judgment after manual triggerKVO
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { if ([key isEqualToString:@"age"]) { return NO; } return [super automaticallyNotifiesObserversForKey:key]; } - (void)setAge:(NSInteger)age { if (age >= 18) { [self willChangeValueForKey:@"age"]; _age = age; [self didChangeValueForKey:@"age"]; }else { _age = age; }}Copy the code

Does using KVC change trigger KVO?

  • Will, as long asaccessInstanceVariablesDirectlyreturnYESChanging the value of a member variable via KVC triggers KVO.
  • This indicates that KVC called internallywillChangeValueForKey:Methods anddidChangeValueForKey:methods

Does modifying a member variable directly trigger KVO?

Don’t

KVO crash and protection

Crash cause:

  • The number of KVO additions and removals did not match, and most of them were removed more than registered.
  • The observeddeallocIs still registered with KVO, causing a crash.
  • An observer was added but not implementedobserveValueForKeyPath:ofObject:change:context:

Protection Scheme 1:

  • Use the Facebook open source framework directlyKVOController

Protection Scheme 2:

  • Customize a hash table to record the relationship between the observer and the observed object.
  • usefishhookreplaceaddObserver:forKeyPath:options:context:Before adding, judge whether the same observer already exists before adding, and add only when there is no observer, to avoid the bug caused by repeated triggering.
  • usefishhookreplaceremoveObserver:forKeyPath:andremoveObserver:forKeyPath:contextCheck whether there is a corresponding relationship before removing it. If so, release it.
  • usefishhookreplacedealloc, the implementation ofdeallocCheck whether there are unremoved observers before removing them.

KVC underlying principles

setValue:forKey:The implementation of the

  • To find thesetKey:Methods and_setKey:Method, as long as it finds directly pass parameters, call method;
  • If you don’t find itsetKey:and_setKey:Method, viewaccessInstanceVariablesDirectlyMethod, if returnsNO(Direct access to member variables is not allowed), callsetValue:forUndefineKey:And throw an exceptionNSUnknownKeyException;
  • ifaccessInstanceVariablesDirectlyMethod returnsYES(it has access to its member variables), then look them up in order_key, _isKey, key, isKeyThese four member variables, if found directly assigned value; If no, callsetValue:forUndefineKey:And throw an exceptionNSUnknownKeyException.

valueForKey:The implementation of the

  • In accordance with theGetKey, key, isKeyThe sequential search method, as long as found directly call;
  • If I don’t find it,accessInstanceVariablesDirectlyreturnYES(can access its member variables), in order to find_key, _isKey, key, isKeyThese four member variables, if you find them, you value them; If no member variable is found, callvalueforUndefineKeyAnd throw an exceptionNSUnknownKeyException.
  • accessInstanceVariablesDirectlyreturnNO(does not allow direct access to member variables), then thevalueforUndefineKey:Method and throws an exceptionNSUnknownKeyException;