iOS KVC探索

成员变量、实例变量、属性

代码一.png
  • 成员变量:不会自动生成get、set方法,成员变量不能用点语法调用,因为没有set和get方法,只能使用->调用。
  • 属性:属性会自动生成set和get方法,可以使用.语法
  • 实例变量:是一种特殊的成员变量,通过class 声明的成员变量

kvc基础使用

@interface QHPerson : NSObject
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)QHSon *son;
@end

@interface QHSon : NSObject
@property (nonatomic,strong)NSString *nickName;
@end

QHPerson *p = [QHPerson new];
[p setValue:@"qinhan" forKey:@"name"];
NSString *name = [p valueForKey:@"name"];
QHSon *son = [QHSon new];
[p setValue:son forKeyPath:@"son"];
[p setValue:@"sonName" forKeyPath:@"son.nickName"];
NSString *sonName = [p valueForKeyPath:@"son.nickName"];

如果是要多级访问或读取

- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;

kvc赋值过程

我们先来看一下官网的描述

官网描述1.png

1.先查找set,_set两个方法,如果这两个方法都没有实现,执行步骤2
2.查找accessInstanceVariablesDirectly,默认为YES,如果为NO,并且1中的方法也没实现,则会闪退。
3.如果accessInstanceVariablesDirectly为YES.则会按照_,_is,,的顺序给成员变量赋值,如果这4个变量名都没找到,则走4的流程
4.如果上面的变量都没有,则会走setValue:forUndefinedKey:,如果这个方法也没有实现,则会出现异常闪退。我们可以通过这个方法来实现最后的异常处理,防止闪退

kvc取值过程

kvc文档
相比于赋值,取值过程流程相对更加复杂一点
1.先按照get,, is, or _的顺序取值
2.如果第一步的方法都没有找到,则会按照countOfobjectInAtIndexobjectInAtIndex AtIndexes去找

  • 如果找到了其中一个,则会创建一个响应所有NSArray方法的集合代理对象,并返回该对象。如果没有则会执行下一步
    -这些方法通过对应的.countarray[index]objectsAtIndexesobjectAtIndex访问到,前提是必须要实现对应的方法,否则会闪退
    3.如果2都没有实现,查找名为countOfenumeratorOfmemberOf这三个方法(对应于NSSet类定义的原始方法)
    4.如果3都没有找到,则会调用accessInstanceVariablesDirectly,如果为YES,会按照顺序取值,都没有就会闪退。如果为NO,就会跳到6
    5.判断取出的属性值,如果为是对象就会直接返回,如果不是会转成NSNumber返回
  1. valueForUndefinedKey,如果走到这一步没有实现这个方法,则会异常,所以当我们自定义kvc的时候,最好实现这个方法

下面附上nsarray代码

@interface QHArray ()
@property (nonatomic,readwrite,assign) NSUInteger count;

@end

@implementation QHArray

//-(void)incrementCount{
//    NSLog(@"%s",__func__);
//    self.count ++;
//}
-(NSUInteger)countOfNumbers{
    NSLog(@"%s",__func__);
    return self.count;
}

-(id)objectInNumbersAtIndex:(NSUInteger)index{
    //当key使用numbers时,KVC会找到这两个方法。
    NSLog(@"%s",__func__);
    return @(index * 2);
}

- (NSArray *)numbersAtIndexes:(NSIndexSet *)indexes
{
    NSLog(@"%s",__func__);
    return @[@"1",@"2"];
}


-(NSInteger)getNum{
    NSLog(@"%s",__func__);//第一个,自己一个一个注释试
    return 10;
}
-(NSInteger)num{
    NSLog(@"%s",__func__);//第二个
    return 11;
}
-(NSInteger)isNum{
    NSLog(@"%s",__func__);//第三个
    return 12;
}

//实现
    QHArray *arr = [QHArray new];
    
    NSNumber* num =   [arr valueForKey:@"num"];
           NSLog(@"%@",num);
    id ar = [arr valueForKey:@"numbers"];
    
    NSLog(@"ar:%@",ar);
    NSLog(@"0:%@  1:%@",ar[0],ar[1]);
    
    NSIndexSet *sets = [NSIndexSet indexSetWithIndex:1];
    
    NSLog(@"sets:%@", [ar objectsAtIndexes:sets]);

kvc应用场景

1.动态的赋值和取值
setValue:forKey:valueForKey:还有路由setValue:forKeyPath:valueForKeyPath:
2.多值操作(model和字典互转)
结合runtime,获取成员变量的值,可以实现model和字典转换
3.用KVC实现高阶消息传递

//KVC实现高阶消息传递
- (void)transmitMsg{
    NSArray *arrStr = @[@"english", @"franch", @"chinese"];
    NSArray *arrCapStr = [arrStr valueForKey:@"capitalizedString"];
    
    for (NSString *str in arrCapStr) {
        NSLog(@"%@", str);
    }
    NSArray *arrCapStrLength = [arrCapStr valueForKeyPath:@"capitalizedString.length"];
    for (NSNumber *length in arrCapStrLength) {
        NSLog(@"%ld", (long)length.integerValue);
    }
}

你可能感兴趣的:(iOS KVC探索)