Key-value Coding (KVC) is a mechanism enabled by the NSKeyValueCoding informal protocol that objects use to access their properties indirectly, that is, they can access an attribute through a string Key. This indirect access mechanism complements the direct access provided by instance variables and their associated accessor methods.

1.KVC APIintroduce

  • throughkeySet the value/value
- (nullable id)valueForKey:(NSString *) Key; - (void)setValue:(nullable id)value forKey:(NSString *) Key;Copy the code
  • throughkeyPath(i.e.routing) Set the value/value
// the value can be KeyPath - (nullable id)valueForKeyPath:(NSString *) KeyPath; // use KeyPath to set the value - (void)setValue:(nullable id)value forKeyPath:(NSString *) KeyPath;Copy the code
  • Other methods
/ / the default returns YES, said if not found the Set < Key > method, according to _key, _iskey, Key, iskey sequential search members, Set to NO don't search + (BOOL) accessInstanceVariablesDirectly; It can be used to check that the set value is correct, to make a replacement value for an incorrect value, or to reject a new value and return the cause of the error. - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError; // This is the set operation API, there are a series of such apis, if the property is an NSMutableArray, then you can use this method to return. - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key; // If the Key does not exist and KVC cannot find any fields or attributes related to the Key, this method is called. By default, an exception is thrown. - (nullable id)valueForUndefinedKey:(NSString *)key; // Same as the previous method, but this method is set. - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key; // If you set SetValue to nil for a basic datatype such as' int ' 'float', - (void)setNilValueForKey:(NSString *)key; // Input a set of keys, return the values corresponding to the keys, and then return the dictionary, which is used to transfer the Model to the dictionary. - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys; // A dictionary is used to transfer the dictionary to Model, and a dictionary is used to change the key value corresponding to Model. - (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;Copy the code

2.KVC APIuse

Define a model class

#import <Foundation/Foundation.h>
@interface ZBMVVMSimpleModel : NSObject
@property (nonatomic,copy) NSString *name;
@end
NS_ASSUME_NONNULL_END
Copy the code
  • throughkeySet the value/value
- (void)viewDidLoad { [super viewDidLoad]; ZBMVVMSimpleModel *simpleModel = [[ZBMVVMSimpleModel alloc]init]; SimpleModel setValue:@"ios" forKey:@"name"]; /// Value NSString *name = [simpleModel valueForKey:@"name"]; NSLog(@" value -- %@",name); } The console prints the ZCDataAnalytics[2115:497383] value -- iosCopy the code
  • throughkeyPath(i.e.routing) Set the value/value
@interface BOTSimpleModel : NSObject @property (nonatomic,copy) NSString *subject; @end @interface ZBMVVMSimpleModel : NSObject @property (nonatomic,copy) NSString *name; @property (nonatomic,strong) BOTSimpleModel *model; @end - (void)viewDidLoad { [super viewDidLoad]; ZBMVVMSimpleModel *simpleModel = [[ZBMVVMSimpleModel alloc]init]; BOTSimpleModel *model = [[BOTSimpleModel alloc]init]; simpleModel.model = model; // 2, simpleModel setValue:@"Swift" forKeyPath:@"model. Subject "]; NSLog(@"subject --- %@",[simpleModel valueForKeyPath:@"model.subject"]); } Console prints ZCDataAnalytics[2115:497383] subject -- SwiftCopy the code

【 summary 】

  • KeyPath is the equivalent of finding attributes by path, layer by layer down.
  • The key value is set by the property name directly. If you search by path, an error will be reported.

3. Principle of KVC setting

SetValue :forKey: the principle of assignment

Step: When we set setValue:forKey:;

(1) Search firstsetKey:,_setKey:(in order);

Find the elegantly-named setName:

Find _setName:

(2) if there is a direct call, if not, check the accessInstanceVariablesDirectly method;

+ (BOOL)accessInstanceVariablesDirectly{ return YES; //return NO; NSUnkonwKeyException {}Copy the code

(3) If it is accessible, it will search for member variables in the order of _key, _isKey, key, and iskey.

Find _key

Find _isKey

To find the key

Find iskey

④ No NSUnkonwKeyException error was found

【 summary 】 so, setValue: @ 10 forKey: @ “age” to modify the age, the core or should call willChangeValueForKey: key and didChangeValueForKey: key.

4. Principle of KVC value

Step: When we set valueForKey:; (1) The KVC value is searched in the order of getKey, key, iskey, and _key.

(2) there is a direct call, if not found, also check the accessInstanceVariablesDirectly method;

+ (BOOL)accessInstanceVariablesDirectly{ return YES; //return NO; NSUnkonwKeyException {}Copy the code

(3) If it is accessible, it will search for member variables in the order of _key, _isKey, key, and iskey.

④ No NSUnkonwKeyException error was found.

5. To summarize

1. Does modifying attributes via KVC trigger KVO?

Will be triggered. The question is the difference between the following two pieces of code.

ZBMVVMSimpleModel *simpleModel = [[ZBMVVMSimpleModel alloc]init]; simpleModel.name = @"ios"; // --------------- VS ---------------- ZBMVVMSimpleModel *simpleModel = [[ZBMVVMSimpleModel alloc]init]; [simpleModel setValue:@"ios" forKey:@"name"]; - (void)viewDidLoad {[super viewDidLoad]; ZBMVVMSimpleModel *simpleModel = [[ZBMVVMSimpleModel alloc]init]; [simpleModel setValue:@"ios" forKey:@"name"]; / / add to monitor [simpleModel addObserver: self forKeyPath: @ "name" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:**nil**]; Simplemodel. name = @"ios"; [simpleModel setValue:@"swift" forKey:@"name"]; [simpleModel removeObserver:self forKeyPath:@"name"]; } -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context{ NSLog(@"change -- %@",change); } **2022-04-01 15:48:37.910300+0800 ZCDataAnalytics[2383:551351] change -- {** **kind = 1; ** **new = swift; ** **old = ios; * * * * * *}Copy the code

By printing, modifying properties via KVC triggers KVO.

The essence of analysis: they are all the same, can start KVO, will be called [self willChangeValueForKey: key]; And [self didChangeValueForKey: key]; Equivalent to manually starting KVO

// [simpleModel willChangeValueForKey:@"name"];
// simpleModel -> _name = @"swift";
// [simpleModel didChangeValueForKey:@"name"];
Copy the code
2. What is the assignment and value process of KVC? How does it work?

SetKey:, _setKey: (search in order); (2) if there is a direct call, if not, check the accessInstanceVariablesDirectly method; (3) If yes, the access will look for member variables in _key, _isKey, key, iskey order. ④ No NSUnkonwKeyException error was found.

ValueForKey: value principle ① KVC values are searched in the sequence of getKey, key, ISkey, and _key. (2) there is a direct call, if not found, also check the accessInstanceVariablesDirectly method; ③ If the access is available, the system searches for member variables in the order _key, _isKey, key, and iskey. ④ If no member variables are found, an NSUnkonwKeyException error is reported.