KVC

KVC基本使用

KVC赋值取值过程分析和自定义及异常处理

赋值过程:

取值过程:

自定义KVC
#import "NSObject+KVC.h"
#import &ltobjc/runtime.h>

@implementation NSObject (KVC)

- (void)bear_setValue:(nullable id)value forKey:(NSString *)key {
  
    // 判断是否合法
    if (key == nil && key.length == 0) {
        return;
    }
    
    // Key
    NSString* Key = key.capitalizedString;
    
    /// 先找相关方法
    //set:, _set:, setIs:
    NSString* setKey = [NSString stringWithFormat:@"set%@:", Key];
    if ([self respondsToSelector:NSSelectorFromString(setKey)]) {
        [self performSelector:NSSelectorFromString(setKey) withObject:value];
        return;
    }
    
    NSString* _setKey = [NSString stringWithFormat:@"_set%@:", Key];
    if ([self respondsToSelector:NSSelectorFromString(_setKey)]) {
        [self performSelector:NSSelectorFromString(_setKey) withObject:value];
        return;
    }
    
    NSString* setIsKey = [NSString stringWithFormat:@"setIs%@:", Key];
    if ([self respondsToSelector:NSSelectorFromString(setIsKey)]) {
        [self performSelector:NSSelectorFromString(setIsKey) withObject:value];
        return;
    }
    
    if (![self.class accessInstanceVariablesDirectly]) {
        NSException* exception = [NSException exceptionWithName:@"NSUnkonwnKeyException" reason:@"setValue:forUndefineKey" userInfo:nil];
        @throw exception;
    }
    
    /// 再找相关变量
    /// 获取所以成员变量
    unsigned int count = 0;
    Ivar* ivars = class_copyIvarList([self class], &count);
    
    NSMutableArray* arr = [[NSMutableArray alloc] init];
    
    for (int i = 0; i < count; i++) {
        Ivar var = ivars[i];
        const char* varName = ivar_getName(var);
        NSString* name = [NSString stringWithUTF8String:varName];
        [arr addObject:name];
    }
    
    // _ _is  is
    for (int i = 0; i < count; i++) {
        NSString* keyName = arr[i];
        if ([keyName isEqualToString:[NSString stringWithFormat:@"_%@", key]]) {
            object_setIvar(self, ivars[i], value);
            free(ivars);
            return;
        }
    }
    
    for (int i = 0; i < count; i++) {
        NSString* keyName = arr[i];
        if ([keyName isEqualToString:[NSString stringWithFormat:@"__is%@", Key]]) {
            object_setIvar(self, ivars[i], value);
            free(ivars);
            return;
        }
    }
    
    for (int i = 0; i < count; i++) {
        NSString* keyName = arr[i];
        if ([keyName isEqualToString:[NSString stringWithFormat:@"%@", key]]) {
            object_setIvar(self, ivars[i], value);
            free(ivars);
            return;
        }
    }
    
    for (int i = 0; i < count; i++) {
        NSString* keyName = arr[i];
        if ([keyName isEqualToString:[NSString stringWithFormat:@"is%@", Key]]) {
            object_setIvar(self, ivars[i], value);
            free(ivars);
            return;
        }
    }
    
    [self setValue:value forUndefinedKey:key];
    free(ivars);
    

}

@end

异常处理:

正确性验证

NSNumber* value = @200;
    if ([p validateValue:&value forKey:@"age" error:NULL]) {
        [p setValue:value forKey:@"age"];
    }

KVC进阶用法

KVC与字典

- (void) dictionaryTest {
    TZPerson* p = [TZPerson new];

    NSDictionary* dict = @{
                           @"name":@"Tom",
                           @"age":@18,
                           @"nick":@"Cat",
                           @"height":@180,
                           @"dd":@"helo"
                           };
    
    [p setValuesForKeysWithDictionary:dict];
    NSLog(@"p.name = %@, p.age = %d, p.nick =%@, p.height = %f", p.name, p.age, p.nick, p.height);
    
    NSArray* keys = @[@"name", @"age"];
    NSDictionary* dict1 = [p dictionaryWithValuesForKeys:keys];
    
    NSLog(@"%@", dict1);
} 

KVC的消息传递

/// KVC消息传递  array
- (void) arrayKVCTest {
    NSArray* arr = @[@"Monday", @"Tuesday", @"Wednesday"];
    //相当于给每个成员d发送length消息
    NSArray* lengthArr = [arr valueForKey:@"length"];
    NSLog(@"%@", lengthArr);
    //发送变小写、消息
    NSArray* lowercaseArr = [arr valueForKey:@"lowercaseString"];
    NSLog(@"%@", lowercaseArr);
}

KVC容器操作

/// 聚合操作符 公式:valueForKeyPath:@+集合操作符+.路径
// @avg、@count、@max、@min、@sum
- (void) contrainerTest {

    NSMutableArray* students = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        TZPerson* student = [TZPerson new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"height":@(1.65 + 0.02*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [students addObject:student];
    }
    //获取所有成员
    NSLog(@"%@", [students valueForKey:@"height"]);
    
    /// 平均身高
    float avg = [[students valueForKeyPath:@"@avg.height"] floatValue];
    NSLog(@"%f", avg);
}

/// 数组操作符 @distinctUnionOfObjects @unionOfObjects
- (void) contrainerArrayTest {
  
    NSMutableArray* students = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        TZPerson* student = [TZPerson new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"height":@(1.65 + 0.02*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [students addObject:student];
    }
    
    NSLog(@"%@", [students valueForKey:@"height"]);
    
    //数组去重distinctUnionOfObjects
    NSArray* arr = [students valueForKeyPath:@"@distinctUnionOfObjects.height"];
    NSLog(@"arr = %@", arr);
    //不去重
    NSArray* arr1 = [students valueForKeyPath:@"@unionOfObjects.height"];
    NSLog(@"arr1 = %@", arr1);
  }

/// 嵌套集合(array&set)操作 @distinctUnionOfArrays @unionOfArrays @distinctUnionOfSets
- (void) containerNestingTest {
  
    NSMutableArray* students = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        TZPerson* student = [TZPerson new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"height":@(1.65 + 0.02*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [students addObject:student];
    }
    
    NSMutableArray* students1 = [NSMutableArray array];
    for (int i = 0; i < 6; i++) {
        TZPerson* student = [TZPerson new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"height":@(1.65 + 0.02*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [students1 addObject:student];
    }
    
    // 嵌套数组
    NSArray* nestArr = @[students, students1];
    //去重
    NSArray* arr = [nestArr valueForKeyPath:@"@distinctUnionOfArrays.height"];
    NSLog(@"arr = %@", arr);
    //不去重
    NSArray* arr1 = [nestArr valueForKeyPath:@"@unionOfArrays.height"];
    NSLog(@"arr1 = %@", arr1);
  }

- (void) containerNestingTest1 {
  
    NSMutableSet* students = [NSMutableSet set];
    for (int i = 0; i < 6; i++) {
        TZPerson* student = [TZPerson new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"height":@(1.65 + 0.02*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [students addObject:student];
    }
    
    NSLog(@"students = %@", [students valueForKey:@"height"]);
    
    NSMutableSet* students1 = [NSMutableSet set];
    for (int i = 0; i < 6; i++) {
        TZPerson* student = [TZPerson new];
        NSDictionary* dict = @{
                               @"name":@"Tom",
                               @"age":@(18+i),
                               @"nick":@"Cat",
                               @"height":@(1.65 + 0.02*arc4random_uniform(6)),
                               };
        [student setValuesForKeysWithDictionary:dict];
        [students1 addObject:student];
    }
    
     NSLog(@"students1 = %@", [students1 valueForKey:@"height"]);
    
    NSSet* nestSet = [NSSet setWithObjects:students, students1, nil];
    //去重
    NSArray* arr1 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.height"];
    NSLog(@"arr1 = %@", arr1);
  }

KVC集合代理对象

#import <&ltFoundation/Foundation.h>
@interface TZPerson : NSObject
@property (nonatomic, assign) NSUInteger count;
@property (nonatomic, strong) NSMutableArray *penArr;
@end

#import "TZPerson.h"
@implementation TZPerson
- (NSUInteger) countOfBooks {
    return self.count;
    }
- (id) objectInBooksAtIndex:(NSUInteger)index {
    return [NSString stringWithFormat:@"book %lu", index];
    }

// 个数
- (NSUInteger) countOfPens {
    return [self.penArr count];
    }
    // 是否包含这个成员对象
- (id) memberOfPens:(id)object {
    return [self.penArr containsObject:object] ? object : nil;
    }
    // 迭代器
- (id) enumeratorOfPens {
    return [self.penArr objectEnumerator];
    }
    @end

- (void)viewDidLoad {
    [super viewDidLoad];

    TZPerson* p = [TZPerson new];
    p.count = 5;
    NSLog(@"books = %@", [p valueForKey:@"books"]);
    
    p.penArr = [NSMutableArray arrayWithObjects:@"pen0", @"pen1", @"pen2", @"pen3", nil];
    NSSet* set = [p valueForKey:@"pens"];
    NSLog(@"pens = %@", set);
    NSEnumerator* enumerator = [set objectEnumerator];
    NSString* str = nil;
    while (str = [enumerator nextObject]) {
        NSLog(@"%@", str);
    }
    }