Speaking of KVC compared to everyone is very familiar with it, here is not much explanation. Let’s go straight to the official documents

Basically, key-value encoding is a mechanism enabled by the NSKeyValueCoding informal protocol that objects use to access their properties indirectly. A property can be accessed through a string key. This indirect access mechanism complements the direct access provided by instance variables and their associated accessor methods.

API methods

- (void)setValue:(nullable id)value forKey:(NSString *)key; - (nullable id)valueForKey:(NSString *)key; // set the value to keyPath in valueForKeyPath - (nullable id)valueForKeyPath:(NSString *)keyPath; // keyPath - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;Copy the code

We’ve been using methods, but we don’t all know what the logic is, so let’s look at the underlying logic and continue to look at the documentation, okay

Search Pattern for the Basic Setter The default implementation of `setValue:forKey:`, given `key` and `value` parameters as input, attempts to set a property named `key` to `value` (or, for non-object properties, the unwrapped version of `value`, as described in [Representing Non-Object Values](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/KeyValueCoding/DataTypes.html#//apple _ref/doc/uid/20002171-BAJEAIEE)) inside the object receiving the call, using the following procedure: 1. Look for the first accessor named `set<Key>:` or `_set<Key>`, in that order. If found, invoke it with the input value (or unwrapped value, as needed) and finish. 2. If no simple accessor is found, and if the class method `accessInstanceVariablesDirectly` returns `YES`, look for an instance variable with a name like `_<key>`, `_is<Key>`, `<key>`, or `is<Key>`, in that order. If found, set the variable directly with the input value (or unwrapped value) and finish. 3. Upon finding no accessor or instance variable, invoke `setValue:forUndefinedKey:`. This raises an exception by default, but a subclass of `NSObject` may provide key-specific behavior.Copy the code

SetValue :forKey Step for setting a value

1. Find the first accessor named set<Key>: or _set<Key>, setIs<Key>, in that order. If it is found, it is called with the input value (or unwrapped value as needed) and done. 2. If you don't find a simple accessor, and accessinstancevariablesdirect () method returns YES if the class, please look for an instance variable, the name of _ < key >, _is < key >, < the key >, or is < key >. If found, set the variable directly with the input value (or unwrapped value) and finish. 3. When found no accessor or instance variables, called setValue: forUndefinedKey:. By default, this throws an exception, but subclasses of NSObject may provide key-specific behavior.Copy the code

So let’s go ahead and verify that we’re doing this right first we’re creating a LGPerson class and we’re creating a name member variable, but again, we can’t use attributes, the element attributes will automatically generate a set method, so we can’t test out the flow. We create a Person object and call setValue:forKey: to set the value to name

LGPerson *person = [[LGPerson alloc] init]; Person setValue:@"LG_Cooci" forKey:@"name"]; person setValue:@"LG_Cooci" forKey:@"name"]Copy the code

Implement the following methods in the LGPerson class

MARK: / / * * * * - - setKey. Process analysis (void) elegantly-named setName (nsstrings *) name {NSLog (@ - % @ "% s", __func__, name); } - (void)_setName:(NSString *)name{ NSLog(@"%s - %@",__func__,name); } - (void)setIsName:(NSString *)name{ NSLog(@"%s - %@",__func__,name); } / / not call - (void) _setIsName: (nsstrings *) name {NSLog (@ - % @ "% s", __func__, name); }Copy the code

Run to find print

**002 -kvc value & assignment process [66533:1767405] -[LGPerson setName:] -lg_COOci **Copy the code

So let’s comment out the setName: method and see what happens

**002-KVC value & assignment process [66641:1771714] -[LGPerson _setName:] - LG_Cooci**Copy the code

Comment out the _setName: method after leaving the _setName: method

**002-KVC value & assignment process [6666:1772607] -[LGPerson setIsName:] - LG_Cooci**Copy the code

The setIsName: method is used, but there is no setIsName: method in the first step in the documentation above, so we need to add this method. Next comment out the setIsName: method. _setIsName: does not go. So the next to go in the document the second step Check the accessInstanceVariablesDirectly whether this method returns YES, note the default is to return here to see the API YES, so continue to analysis began to find an instance variable, its name followed by _Name, _isName,, or isName. We create four member variables in LGPerson: _name,_isName,name,isName. Now let’s look at it by printing

LGPerson *person = [[LGPerson alloc] init]; Person setValue:@"LG_Cooci" forKey:@"name"]; person setValue:@"LG_Cooci" forKey:@"name"] NSLog(@"%@-%@-%@-%@",person->_name,person->_isName,person->name,person->isName);Copy the code

The printed result is

* * 002 - KVC values & assignment process [66803-1779080] LG_Cooci - (null) - (null) - * * (null)Copy the code

Select * from ‘_name’; select * from ‘_name’; Next we comment out the _name member variable and see the print

LGPerson *person = [[LGPerson alloc] init]; Person setValue:@"LG_Cooci" forKey:@"name"]; person setValue:@"LG_Cooci" forKey:@"name"] NSLog(@"%@-%@-%@",person->_isName,person->name,person->isName);Copy the code
**002 -kvc value & Assignment process [66875:1782337] LG_Cooci-(null)-(null)**Copy the code

_isName does have a value, so it shows that _isName is found underneath; I’m going to comment out name and isName to verify that, so I’m not going to bother you here, but you can test it yourself. And then we comment out all the member variables and then we run it and it crashes

The system call setValue: forUndefinedKey: method throws an exception.

Through the code flow of appeal, we have fully verified the bottom lookup flow of setValue:forKey:.

ValueForKey: value flow

1. Search the instance for accessor methods of get<Key>, <Key>, is<Key>, and _< Key>. If yes, return the corresponding value. If no, go to Step 2. 2. Determine whether + (BOOL) accessInstanceVariablesDirectly function returns YES, find the corresponding value is returned), can't find into the third step; If accessInstanceVariablesDirectly whether returns YES is NO return, is as in step 3. 3. If no, call valueForUndefinedKey to throw an exception.Copy the code

Code validation

Person ->name = @"name"; NSLog(@" value :%@",[person valueForKey:@"name"]); LGPerson. M / / MARK: -valueForKey Process analysis -get <Key>, <Key>, is<Key>, or _< Key> - (NSString *)getName{return NSStringFromSelector(_cmd); } - (NSString *)name{ return NSStringFromSelector(_cmd); } - (NSString *)isName{ return NSStringFromSelector(_cmd); } - (NSString *)_name{ return NSStringFromSelector(_cmd); }Copy the code

We can verify that the flow is correct by following the setValue:forKey: validation method above, so let’s play with the test. If not, let’s continue looking for the member variable

Person ->_name = @"_name"; person->_isName = @"_isName"; person->name = @"name"; person->isName = @"isName"; NSLog(@" value :%@",[person valueForKey:@"name"]);Copy the code

I’m going to comment it out and see what it looks like, and I’m going to comment it out and I’m going to comment out all the member variables in LGPerson, or I’m going to print null, because if I can find _name, I’m not going to go any further, but I’m going to say person->_name = @”_name”; The value of _name is commented out, so null is printed.