KVO & KVC
KVO
Usage and underlying principles
- Usage: Add observer, then how to implement listening proxy
KVO
The bottom layer usesisa-swizling
The technology.OC
For each object/class inisa
A pointer,isa
Represents 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’sisa
The pointer points to the middle class. - And then the middle class will be rewritten
setter
Method, callsetter
Before the callwillChangeValueForKey
, the callsetter
After the calldidChangeValueForKey
To notify all observers that the value has changed. - Rewrite the
-class
Method, 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 example
view & 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 passes
string
Type 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 method
if
judge - 3. Forgetting to remove an observer or repeatedly removing an observer can cause
crash
How to trigger it manuallyKVO
KVO
The mechanism is throughwillChangeValueForKey:
anddidChangeValueForKey:
Triggered by two methods.- Called before observing object changes
willChangeValueForKey:
- Called after observing object changes
didChangeValueForKey:
- So you only need to call it manually before and after changing the observation value.
Add filter criteria to KVO
- rewrite
automaticallyNotifiesObserversForKey
, need to be screenedkey
returnNO
. setter
Add 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 as
accessInstanceVariablesDirectly
returnYES
Changing the value of a member variable via KVC triggers KVO. - This indicates that KVC called internally
willChangeValueForKey:
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 observed
dealloc
Is still registered with KVO, causing a crash. - An observer was added but not implemented
observeValueForKeyPath:ofObject:change:context:
。
Protection Scheme 1:
- Use the Facebook open source framework directly
KVOController
Protection Scheme 2:
- Customize a hash table to record the relationship between the observer and the observed object.
- use
fishhook
replaceaddObserver: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. - use
fishhook
replaceremoveObserver:forKeyPath:
andremoveObserver:forKeyPath:context
Check whether there is a corresponding relationship before removing it. If so, release it. - use
fishhook
replacedealloc
, the implementation ofdealloc
Check whether there are unremoved observers before removing them.
KVC underlying principles
setValue:forKey:
The implementation of the
- To find the
setKey:
Methods and_setKey:
Method, as long as it finds directly pass parameters, call method; - If you don’t find it
setKey:
and_setKey:
Method, viewaccessInstanceVariablesDirectly
Method, if returnsNO
(Direct access to member variables is not allowed), callsetValue:forUndefineKey:
And throw an exceptionNSUnknownKeyException
; - if
accessInstanceVariablesDirectly
Method returnsYES
(it has access to its member variables), then look them up in order_key, _isKey, key, isKey
These four member variables, if found directly assigned value; If no, callsetValue:forUndefineKey:
And throw an exceptionNSUnknownKeyException
.
valueForKey:
The implementation of the
- In accordance with the
GetKey, key, isKey
The sequential search method, as long as found directly call; - If I don’t find it,
accessInstanceVariablesDirectly
returnYES
(can access its member variables), in order to find_key, _isKey, key, isKey
These four member variables, if you find them, you value them; If no member variable is found, callvalueforUndefineKey
And throw an exceptionNSUnknownKeyException
. accessInstanceVariablesDirectly
returnNO
(does not allow direct access to member variables), then thevalueforUndefineKey:
Method and throws an exceptionNSUnknownKeyException
;