preface

KVC, also known as key-value Coding, is a common technical point in iOS development. It is believed that many developers have used KVC. The two main methods of KVC are as follows, respectively corresponding to setting Value and Value:

  • (void)setValue:(nullable id)value forKey:(NSString *)key;
  • (nullable id)valueForKey:(NSString *)key;

oneKVCSimple application

    LGPerson *person = [[LGPerson alloc] init];

    // The general setter method

    person.name      = @"LG_Cooci"; // setter -- llvm

    person.age       = 18;

    person->myName   = @"cooci";

    NSLog(@"%@ - %d - %@",person.name,person.age,person->myName);

   

    // 1: key-value Coding (KVC) : basic type - see the underlying principle

    // Informal protocol - indirect access

    [person setValue:@"KC" forKey:@"name"];

    

    // 2:KVC - set type

    person.array = @[@"1"The @"2"The @"3"];

    // Modify the array

    // person.array[0] = @"100";

    // Make a new array. -kvc: OK

    NSArray *array = [person valueForKey:@"array"];

    array = @[@"100"The @"2"The @"3"];

    [person setValue:array forKey:@"array"];

    NSLog(@"% @",[person valueForKey:@"array"]);

    / / the second

    NSMutableArray *mArray = [person mutableArrayValueForKey:@"array"];

    mArray[0] = @"200";

    NSLog(@"% @",[person valueForKey:@"array"]);
    // 3:KVC - set operator
    // 4:KVC - Access non-object attributes - interview may be asked
    / / structure

    ThreeFloats floats = {1..2..3.};

    NSValue *value     = [NSValue valueWithBytes:&floats objCType: **@encode**(ThreeFloats)];

    [person setValue:value forKey:@"threeFloats"];

    NSValue *value1    = [person valueForKey:@"threeFloats"];

    NSLog(@"% @",value1);


    ThreeFloats th;

    [value1 getValue:&th];

    NSLog(@"%f-%f-%f",th.x,th.y,th.z);

    // 5:KVC - layer access - keyPath

    LGStudent *student = [LGStudent alloc];

    student.subject    = @"Master Class";

    person.student     = student;

    [person setValue:@"Swift" forKeyPath:@"student.subject"];

    NSLog(@"% @",[person valueForKeyPath:@"student.subject"]);
Copy the code
#pragma mark ** -array value **- (**void**)arrayDemo{

    LGStudent *p = [LGStudent new];

    p.penArr = [NSMutableArray arrayWithObjects:@"pen0"The @"pen1"The @"pen2"The @"pen3", **nil**];

    NSArray *arr = [p valueForKey:@"pens"]; // Dynamic member variables

    NSLog(@"pens = %@", arr);

    //NSLog(@"%@",arr[0]);

    NSLog(@"%d",[arr containsObject:@"pen9"]);

    / / traverseNSEnumerator *enumerator = [arr objectEnumerator]; NSString* str = **nil**; 六四运动while** (str = [enumerator nextObject]) {

        NSLog(@"% @", str); }} #pragma mark **- - (**void**)dictionaryTest{

    

    NSDictionary* dict = @{

                           @"name": @"Cooci"The @"nick": @"KC"The @"subject": @"iOS"The @"age": @18The @"length": @180

                           };

    LGStudent *p = [[LGStudent alloc] init];

    // Dictionary transfer model

    [p setValuesForKeysWithDictionary:dict];

    NSLog(@"% @",p);

    // Turn the key array into a dictionary

    NSArray *array = @[@"name"The @"age"];

    NSDictionary *dic = [p dictionaryWithValuesForKeys:array];

    NSLog(@"% @",dic); } #pragma mark ** -kvc message passing **- (**void**)arrayMessagePass{

    NSArray *array = @[@"Hank"The @"Cooci"The @"Kody"The @"CC"];

    NSArray *lenStr= [array valueForKeyPath:@"length"];

    NSLog(@"% @",lenStr);// The message is passed from array to string

    NSArray *lowStr= [array valueForKeyPath:@"lowercaseString"];

    NSLog(@"% @",lowStr); } #pragma mark **- aggregate operator **@avg, @count, @max, @min, @sum- (* *void**)aggregationOperator{ NSMutableArray *personArray = [NSMutableArray array]; 六四运动for** (**int** i = 0; i < 6; i++) {

        LGStudent *p = [LGStudent new];

        NSDictionary* dict = @{

                               @"name": @"Tom"The @"age": @ (18+i),

                               @"nick": @"Cat"The @"length": @ (175 + 2*arc4random_uniform(6)),}; [p setValuesForKeysWithDictionary:dict]; [personArray addObject:p]; } NSLog(@"% @", [personArray valueForKey:@"length"]);

    

    /// Average height

    **float** avg = [[personArray valueForKeyPath:@"@avg.length"] floatValue];

    NSLog(@"%f", avg);

    

    **int** count = [[personArray valueForKeyPath:@"@count.length"] intValue];

    NSLog(@"%d", count);

    

    **int** sum = [[personArray valueForKeyPath:@"@sum.length"] intValue];

    NSLog(@"%d", sum);

    

    **int** max = [[personArray valueForKeyPath:@"@max.length"] intValue];

    NSLog(@"%d", max);

    

    **int** min = [[personArray valueForKeyPath:@"@min.length"] intValue];

    NSLog(@"%d", min);

}

// The array operator @distinctUnionOfObjects @UnionOfObjects- (* *void**)arrayOperator{ NSMutableArray *personArray = [NSMutableArray array]; 六四运动for** (**int** i = 0; i < 6; i++) {

        LGStudent *p = [LGStudent new];

        NSDictionary* dict = @{

                               @"name": @"Tom"The @"age": @ (18+i),

                               @"nick": @"Cat"The @"length": @ (175 + 2*arc4random_uniform(6)),}; [p setValuesForKeysWithDictionary:dict]; [personArray addObject:p]; } NSLog(@"% @", [personArray valueForKey:@"length"]);

    // Returns a collection of the specified properties of the operation object

    NSArray* arr1 = [personArray valueForKeyPath:@"@unionOfObjects.length"];

    NSLog(@"arr1 = %@", arr1);

    // Return a collection of the specified properties of the operation object

    NSArray* arr2 = [personArray valueForKeyPath:@"@distinctUnionOfObjects.length"];

    NSLog(@"arr2 = %@", arr2);

    

}
// Nested sets (array&Set) operate @distinctUnionOfArrays @unionOfArrays @distinctUnionOfSets- (* *void**)arrayNesting{ NSMutableArray *personArray1 = [NSMutableArray array]; 六四运动for** (**int** i = 0; i < 6; i++) {

        LGStudent *student = [LGStudent new];

        NSDictionary* dict = @{

                               @"name": @"Tom"The @"age": @ (18+i),

                               @"nick": @"Cat"The @"length": @ (175 + 2*arc4random_uniform(6)),}; [student setValuesForKeysWithDictionary:dict]; [personArray1 addObject:student]; } NSMutableArray *personArray2 = [NSMutableArray array]; 六四运动for** (**int** i = 0; i < 6; i++) {

        LGPerson *person = [LGPerson new];

        NSDictionary* dict = @{

                               @"name": @"Tom"The @"age": @ (18+i),

                               @"nick": @"Cat"The @"length": @ (175 + 2*arc4random_uniform(6)),}; [person setValuesForKeysWithDictionary:dict]; [personArray2 addObject:person]; }// Nested arrays

    NSArray* nestArr = @[personArray1, personArray2];

    

    NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.length"];

    NSLog(@"arr = %@", arr);

    

    NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.length"];

    NSLog(@"arr1 = %@", arr1); } - (* *void**)setNesting{ NSMutableSet *personSet1 = [NSMutableSet set]; 六四运动for** (**int** i = 0; i < 6; i++) {

        LGStudent *person = [LGStudent new];

        NSDictionary* dict = @{

                               @"name": @"Tom"The @"age": @ (18+i),

                               @"nick": @"Cat"The @"length": @ (175 + 2*arc4random_uniform(6)),}; [person setValuesForKeysWithDictionary:dict]; [personSet1 addObject:person]; } NSLog(@"personSet1 = %@", [personSet1 valueForKey:@"length"]); NSMutableSet *personSet2 = [NSMutableSet set]; 六四运动for** (**int** i = 0; i < 6; i++) {

        LGPerson *person = [LGPerson new];

        NSDictionary* dict = @{

                               @"name": @"Tom"The @"age": @ (18+i),

                               @"nick": @"Cat"The @"length": @ (175 + 2*arc4random_uniform(6)),}; [person setValuesForKeysWithDictionary:dict]; [personSet2 addObject:person]; } NSLog(@"personSet2 = %@", [personSet2 valueForKey:@"length"]);
    / / nested set
    NSSet* nestSet = [NSSet setWithObjects:personSet1, personSet2, **nil**];
    / / intersection
    NSArray* arr1 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.length"];
    NSLog(@"arr1 = %@", arr1);
}

Copy the code

twoKVCIntroduction – Official Apple documents important

Apple develops iOS addresses

3. Apple official document explanationKVC

KVC address

Four.KVCSet values and the process of setting values

KVC set

KVC The process of setting a value

Set

:-> _set< Key>:

When accessInstanceVariablesDirectly set to YES for instance variable sequence in order to find the name is _ < key > – > _is < key > — > < key > – > is < key >

_<key> _is<Key>

<key>

is<Key>

According to the official document, if none of the above is available, the following method will be entered

The process of KVC value

Get

->< Key>-> is

->_< Key>


->_is< key>->

->is< key

When we comment out _name and print name, the _isName sequence is displayed

If none of them are there then valueForUndefinedKey: is called

Five.KVCCustom implementation

- (* *void**)lg_setValue:(**nullable** **id**)value forKey:(NSString *)key{

    // KVC custom

    // 1: What is the key六四运动if** (key == **nil** || key.length == 0) {

        **return* *; }// 2: setter set<Key>: or _set<Key>,

    // Capitalize key

    NSString *Key = key.capitalizedString;

    // Splice method

    NSString *setKey = [NSString stringWithFormat:@"set%@:",Key];

    NSString *_setKey = [NSString stringWithFormat:@"_set%@:",Key];

    NSString *setIsKey = [NSString stringWithFormat:@"setIs%@:",Key]; 六四运动if** ([**self** lg_performSelectorWithMethodName:setKey value:value]) {

        NSLog(@"* * * * * * * * * % @ * * * * * * * * * *",setKey); 六四运动return* *; } * *else* * * *if** ([**self** lg_performSelectorWithMethodName:_setKey value:value]) {

        NSLog(@"* * * * * * * * * % @ * * * * * * * * * *",_setKey); 六四运动return* *; } * *else* * * *if** ([**self** lg_performSelectorWithMethodName:setIsKey value:value]) {

        NSLog(@"* * * * * * * * * % @ * * * * * * * * * *",setIsKey); 六四运动return* *; }/ / 3: determine whether response accessInstanceVariablesDirectly returns YES NO collapses

    // 3: determines whether an instance variable can be assigned directly六四运动if* * (! [**self**.class accessInstanceVariablesDirectly] ) { **@throw** [NSException exceptionWithName:@"LGUnknownKeyException" reason:[NSString stringWithFormat:@"****[%@ valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.****",**self**] userInfo:**nil**];

    }
    // 4: indirect variable

    // Get ivar -> iterate over containsObjct -

    // 4.1 Define a mutable array to collect instance variables

    NSMutableArray *mArray = [**self** getIvarListName];

    // _<key> _is<Key> <key> is<Key>

    NSString *_key = [NSString stringWithFormat:@"_ % @",key];

    NSString *_isKey = [NSString stringWithFormat:@"_is%@",Key];

    NSString *isKey = [NSString stringWithFormat:@"is%@",Key]; 六四运动if** ([mArray containsObject:_key]) {

        // 4.2 Obtaining the corresponding IVAR

       Ivar ivar = class_getInstanceVariable([**self** class]._key.UTF8String);

        // 4.3 Setting the ivAR valueobject_setIvar(**self** , ivar, value); 六四运动return* *; } * *else* * * *if** ([mArray containsObject:_isKey]) {

       Ivar ivar = class_getInstanceVariable([**self** class]._isKey.UTF8String); object_setIvar(**self** , ivar, value); 六四运动return* *; } * *else* * * *if** ([mArray containsObject:key]) {

       Ivar ivar = class_getInstanceVariable([**self** class].key.UTF8String); object_setIvar(**self** , ivar, value); 六四运动return* *; } * *else* * * *if** ([mArray containsObject:isKey]) {

       Ivar ivar = class_getInstanceVariable([**self** class].isKey.UTF8String); object_setIvar(**self** , ivar, value); 六四运动return* *; }// 5: If no relevant instance is found* * @throw** [NSException exceptionWithName:@"LGUnknownKeyException" reason:[NSString stringWithFormat:@"****[%@ %@]: this class is not key value coding-compliant for the key name.****",**self**,NSStringFromSelector( **_cmd**)] userInfo:**nil**];

    

}
- (**nullable** **id**)lg_valueForKey:(NSString *)key{

    

    // 1: the brush key is not empty六四运动if** (key == **nil**  || key.length == 0) {

        **return** **nil**;

    }

    Get 
      
         countOf
        
          objectIn
         
          AtIndex
         

    // Capitalize key

    NSString *Key = key.capitalizedString;

    // Splice method

    NSString *getKey = [NSString stringWithFormat:@"get%@",Key];

    NSString *countOfKey = [NSString stringWithFormat:@"countOf%@",Key];

    NSString *objectInKeyAtIndex = [NSString stringWithFormat:@"objectIn%@AtIndex:",Key];

        

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"六四运动if** ([**self** respondsToSelector:NSSelectorFromString(getKey)]) {

        **return** [**self** performSelector:NSSelectorFromString(getKey)]; } * *else* * * *if** ([**self** respondsToSelector:NSSelectorFromString(key)]){

        **return** [**self** performSelector:NSSelectorFromString(key)]; } * *else* * * *if** ([**self** respondsToSelector:NSSelectorFromString(countOfKey)]){

        **if** ([**self** respondsToSelector:NSSelectorFromString(objectInKeyAtIndex)]) {

            **int** num = (**int**)[**self** performSelector:NSSelectorFromString(countOfKey)];

            NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1]; 六四运动for** (**int** i = 0; i<num-1; i++) { num = (**int**)[**self** performSelector:NSSelectorFromString(countOfKey)]; } * *for** (**int** j = 0; j<num; j++) { **id** objc = [**self** performSelector:NSSelectorFromString(objectInKeyAtIndex) withObject:@(num)]; [mArray addObject:objc]; } * *return** mArray;

        }

    }

#pragma clang diagnostic pop

    

    // 3: determines whether an instance variable can be assigned directly六四运动if* * (! [**self**.class accessInstanceVariablesDirectly] ) { **@throw** [NSException exceptionWithName:@"LGUnknownKeyException" reason:[NSString stringWithFormat:@"****[%@ valueForUndefinedKey:]: this class is not key value coding-compliant for the key name.****",**self**] userInfo:**nil**];

    }

    

    // 4. Find the related instance variables and assign values

    // 4.1 Define a mutable array to collect instance variables

    NSMutableArray *mArray = [**self** getIvarListName];

    // _<key> _is<Key> <key> is<Key>

    // _name -> _isName -> name -> isName

    NSString *_key = [NSString stringWithFormat:@"_ % @",key];

    NSString *_isKey = [NSString stringWithFormat:@"_is%@",Key];

    NSString *isKey = [NSString stringWithFormat:@"is%@",Key]; 六四运动if** ([mArray containsObject:_key]) {

        Ivar ivar = class_getInstanceVariable([**self** class]._key.UTF8String); 六四运动return** object_getIvar(**self**, ivar);; } * *else* * * *if** ([mArray containsObject:_isKey]) {

        Ivar ivar = class_getInstanceVariable([**self** class]._isKey.UTF8String); 六四运动return** object_getIvar(**self**, ivar);; } * *else* * * *if** ([mArray containsObject:key]) {

        Ivar ivar = class_getInstanceVariable([**self** class].key.UTF8String); 六四运动return** object_getIvar(**self**, ivar);; } * *else* * * *if** ([mArray containsObject:isKey]) {

        Ivar ivar = class_getInstanceVariable([**self** class].isKey.UTF8String); 六四运动return** object_getIvar(**self**, ivar);; } * *return* * @""; } # pragma mark - related methods * * - * * * * BOOL (* *) lg_performSelectorWithMethodName: (nsstrings *) methodName value: * * * * id value {* *if** ([**self** respondsToSelector:NSSelectorFromString(methodName)]) {

        

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"

        [**self** performSelector:NSSelectorFromString(methodName) withObject:value];

#pragma clang diagnostic pop

        **return** **YES**; } * *return** **NO**;

}
- (**id**)performSelectorWithMethodName:(NSString *)methodName{

    **if** ([**self** respondsToSelector:NSSelectorFromString(methodName)]) {

#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-performSelector-leaks"六四运动return** [**self** performSelector:NSSelectorFromString(methodName) ];

#pragma clang diagnostic pop

    }

    **return** **nil**;

}
- (NSMutableArray *)getIvarListName{

    

    NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:1];

    **unsigned** **int** count = 0;

    Ivar *ivars = class_copyIvarList([**self** class], &count); 六四运动for** (**int** i = 0; i<count; i++) { Ivar ivar = ivars[i]; 六四运动const** **char** *ivarNameChar = ivar_getName(ivar);

        NSString *ivarName = [NSString stringWithUTF8String:ivarNameChar];

        NSLog(@"ivarName == %@",ivarName); [mArray addObject:ivarName]; } free(ivars); 六四运动return** mArray;

}
Copy the code

Vi.KVC expansion and summary