Differences between KVC and KVO in iOS and iOSKVCKVO
The two concepts KVC and KVO are often seen in iOS development, which may be confused.
KVC (Key Value Coding) 1> Overview
KVC: Key Value Coding, which is used to indirectly access instance variables.
KVC provides a mechanism to access an object instance variable by using a string (Key) instead of an accessor method.
2> some KVC source code (header files)
1 // NSKeyValueCoding.h 2 @interface NSObject(NSKeyValueCoding) 3 4 + (BOOL)accessInstanceVariablesDirectly; 5 6 - (nullable id)valueForKey:(NSString *)key; 7 - (void)setValue:(nullable id)value forKey:(NSString *)key; 8 - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError; 9 10 - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;11 12 - (NSMutableOrderedSet *)mutableOrderedSetValueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);13 14 - (NSMutableSet *)mutableSetValueForKey:(NSString *)key;15 16 - (nullable id)valueForKeyPath:(NSString *)keyPath;17 - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;18 - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKeyPath:(NSString *)inKeyPath error:(out NSError **)outError;19 - (NSMutableArray *)mutableArrayValueForKeyPath:(NSString *)keyPath;20 - (NSMutableOrderedSet *)mutableOrderedSetValueForKeyPath:(NSString *)keyPath NS_AVAILABLE(10_7, 5_0);21 - (NSMutableSet *)mutableSetValueForKeyPath:(NSString *)keyPath;22 23 - (nullable id)valueForUndefinedKey:(NSString *)key;24 - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;25 - (void)setNilValueForKey:(NSString *)key;26 - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;27 - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;28 29 @end30 31 @interface NSArray<ObjectType>(NSKeyValueCoding)32 33 - (id)valueForKey:(NSString *)key;34 - (void)setValue:(nullable id)value forKey:(NSString *)key;35 36 @end37 38 @interface NSDictionary<KeyType, ObjectType>(NSKeyValueCoding)39 40 - (nullable ObjectType)valueForKey:(NSString *)key;41 42 @end43 44 @interface NSMutableDictionary<KeyType, ObjectType>(NSKeyValueCoding)45 46 - (void)setValue:(nullable ObjectType)value forKey:(NSString *)key;47 48 @end49 50 @interface NSOrderedSet<ObjectType>(NSKeyValueCoding)51 52 - (id)valueForKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);53 - (void)setValue:(nullable id)value forKey:(NSString *)key NS_AVAILABLE(10_7, 5_0);54 55 @end56 57 @interface NSSet<ObjectType>(NSKeyValueCoding)58 59 - (id)valueForKey:(NSString *)key;60 - (void)setValue:(nullable id)value forKey:(NSString *)key;61 62 @end
The class contains extensions for NSObject, NSArray, NSDictionary, NSMutableDictionary, NSOrderedSet, and NSSet.
- (id)valueForKey:(NSString *)key;- (void)setValue:(nullable id)value forKey:(NSString *)key;
That is to say, basically all objects in Objective-C areSupport for KVC
The operation includes the above two methods, dynamic reading and dynamic setting.
3> access attributes through KVC key-value Encoding
① Key value search
1 [stu setValue:@"xiaoqiang" forKey:@"name"]; 2 [stu setValue:@"boy" forKey:@"gender"];3 [stu setValue:@24 forKey:@"age"]; 4 5 NSLog(@"name = %@, gender = %@, age = %@", [stu valueForKey:@"name"], [stu valueForKey:@"gender"], [stu valueForKey:@"age"]);
② Path search
1 Teacher * tea = [[Teacher alloc] init]; 2 stu. teacher = tea; 3 [stu setValue: @ "fangfang" forKeyPath: @ "teacher. name "]; 4 5 // search for 6 NSLog (@" teacherName = % @ ", [stu valueForKeyPath: @" teacher. name "]);
③ Assign values to multiple attributes at the same time
1 NSDictionary * dict =@{ 2 @ "name": @ "fangfang", 3 @ "gender": @ "girl", 4 @ "age": @ 18, 5 @ "holobby": @ "fangfang" 6}; 7 Student * stu2 = [Student alloc] init]; 8 9 // assign 10 [stu2 setValuesForKeysWithDictionary: dict] to multiple attributes at the same time; 11 12 NSLog (@ "name =%@, gender =%@, age = % ld ", stu2.name, stu2.gender, stu2.age );
4> KVC throw an exception
① When KVC is used to set a value object
If the current class does not find the Key value of the object, the system will automatically call setValue: forUndefinedKey: Method
The default implementation of this method is to throw an exception. If you do not want to throw an exception, rewrite this method.
1 // rewrite 2 // use KVC to set the value object 3-(void) setValue :( id) value forUndefinedKey :( NSString *) key4 {5 NSLog (@ "Key does not exist: % @ ", key); 6}
② When using the KVC Value
If the corresponding Key value is not found for the current class, the system will automatically call valueForUndefinedKey: Method
The default implementation of this method is to throw an exception. If you do not want to throw an exception, rewrite this method.
1 // rewrite 2 // when KVC is used, 3-(id) valueForUndefinedKey :( NSString *) key4 {5 return nil; 6}
5> Implementation Mechanism of KVC
KVC uses the following techniques in sequence:
- Check whether the getter method-<key> or setter method-set <key>: exists;
- If no such method is available, check whether there are instance variables named-_ <key> and <key>;
- If not found, call valueForUndefinedKey: And setValue: forUndefinedKey: method. The default implementation of these methods throws an exception. We can rewrite them as needed.
KVC (Key Value Observer)
1> Overview
KVO :( Key Value Observer) is a concrete implementation of the Observer design pattern.
KVO trigger mechanism: one object (observer) is used to monitor whether a property of another object (observer) changes. If the property to be monitored changes, will trigger a method of the observer (the method name is fixed, similar to the proxy method)
2> some NSKeyValueObserving. h extended NSObject code
1 @interface NSObject(NSKeyValueObserving) 2 3 - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context; 4 5 @end 6 7 @interface NSObject(NSKeyValueObserverRegistration) 8 9 - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;10 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);11 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;12 13 @end
We can see from the extension name thatUse KVC
You need to register the listener and delete the listener. The observeValueForKeyPath callback method is required during the monitoring process.
3> procedure
Register The Observer (specify the observer and the observed attribute for the observer)
1 // KVO key value observation, is the Observer Design Mode 2 @ interface ViewController () 3 4 // observe the changes of the variable array (it is not recommended to observe the array in Apple's official documentation) 5 @ property (nonatomic, strong) NSMutableArray * array; 6 7 @ end 8 9-(void) viewDidLoad {10 [super viewDidLoad]; 11 // Do any additional setup after loading the view, typically from a nib.12 13 self. array = [NSMutableArray array]; 14 15 // Step 1: Register observer 16 // parameter 1: added observer object 17 // parameter 2: key18 of the string id // parameter 3: 19/* 20 NSKeyValueObservingOptionNew = 0x01 key or value triggers 21 NSKeyValueObservingOptionOld = 0x0222 conflict = 0x0423 conflict = 0x0824 */25 // parameter 4: the text content is generally nil26 [self addObserver: self forKeyPath: @ "array" options: NSKeyValueObservingOptionNew context: nil]; 27}
Callback Implementation Method
1 // Step 2: Implement callback 2-(void) observeValueForKeyPath :( NSString *) keyPath ofObject :( id) object change :( NSDictionary <NSString *, id> *) change context :( void *) context 3 {4 5 NSLog (@ "keyPath = % @", keyPath); 6 NSLog (@ "object = % @", object ); 7 NSLog (@ "change = % @", change); 8 9 // You can refresh the UI 10}
Trigger callback method (observed attribute changes)
1 // Step 2: Implement callback 2-(void) observeValueForKeyPath :( NSString *) keyPath ofObject :( id) object change :( NSDictionary <NSString *, id> *) change context :( void *) context 3 {4 5 NSLog (@ "keyPath = % @", keyPath); 6 NSLog (@ "object = % @", object ); 7 NSLog (@ "change = % @", change); 8 9 // You can refresh the UI 10}
Remove observer
You need to delete the observer when you do not need it. I will only remove it when the view is about to disappear.
1 // when the view is about to disappear 2-(void) viewWillDisappear :( BOOL) animated3 {4 // you need to delete it 5 [self removeObserver: self forKeyPath: @ "array"]; 6}