iOS底层原理之`OC语法`(二.KVC和KVO)

1. KVC

  • KVC的全称是Key-Value Coding,俗称“键值编码”,可以通过一个key来访问某个属性。
  • 常见的API有:
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;//通过keyPath可以设置属性的属性
- (void)setValue:(id)value forKey:(NSString *)key;//通过key设置自己的属性
- (id)valueForKeyPath:(NSString *)keyPath;//通过keyPath访问属性的属性
- (id)valueForKey:(NSString *)key; //通过key访问自己的属性
  • kvc设置属性原理:


    iOS底层原理之`OC语法`(二.KVC和KVO)_第1张图片
    kvc设置属性原理
  • setValue:forKey的原理详解:

    1. 先去寻找setKey:方法(即对应key的set方法),找到了就去传递参数调用方法;
    2. 如果没找到,再去寻找_setKey:的方法,找到可传值;
    3. 没找到就去查看+ (BOOL)accessInstanceVariablesDirectly;这个方法是不是设置为YES(默认是YES),如果设置的是YES这表示直可以接访问实例成员变量;
    4. 然后会去查看有没有_key的成员变量、有就设值;
    5. 没有就去查看有没有_isKey的成员变量、有就设值;
    6. 没有就去查看有没有key的成员变量、有就设值;
    7. 没有就去查看有没有isKey的成员变量、有就设值;
    8. 如果还没找到就会抛异常:NSUnknownKeyException
    9. 如果上面accessInstanceVariablesDirectly设置为NO,并且setKey:、_setKey:这两个set方法没找到就会抛异常,不会去访问属性。
      示例1:
@interface Person : NSObject{
@public
//    int _age;
    int _isAge;
    int age;
    int isAge;

}

/**age属性*/
//@property(nonatomic,assign) int age;
@end

@implementation Person

//-(void)setAge:(int)age{
//    _age = age;
//}
//-(void)_setAge:(int)age{
//    _age = age;
//}
@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        Person * p = [[Person alloc]init];
        [p setValue:@18 forKey:@"age"];
//      NSLog(@"%d",p->age);
        
    }
    return 0;
}

iOS底层原理之`OC语法`(二.KVC和KVO)_第2张图片
kvc设置属性原理

上面代码和调试结果可以看出:当把两个set方法和_age成员变量注销后会优先访问_isAge成员变量,可以通过注销其他的成员变量一次证明方法的顺序,这里不再赘述。

在Person类中重写+ (BOOL)accessInstanceVariablesDirectly;方法,并设置返回值为NO,编译就会抛异常。

@implementation Person
+ (BOOL)accessInstanceVariablesDirectly{
    return NO;
}
@end
iOS底层原理之`OC语法`(二.KVC和KVO)_第3张图片
抛异常.png
  • kvc取值原理:


    iOS底层原理之`OC语法`(二.KVC和KVO)_第4张图片
    kvc取值原理.png
  • valueForKey:原理详解:
  1. 同设置属性一样,取值时访问方法的顺序是getKeykeyisKey_key,找到前面的方法就调用给成员变量取值就不会再往下找了。
  2. 如果上面的方法都没找到就会去查看accessInstanceVariablesDirectly`这个方法是不是设置为YES,如果设置的是YES这表示直可以接访问实例成员变量;
  3. 设置成员变量的顺序为:_key_isKeykeyiskey找到前面的成员变量取值就不会再往下找了;
  4. 如果没有找到上面的成员变量,就会抛异常:NSUnknownKeyException
  5. 如果上面accessInstanceVariablesDirectly设置为NO,并且上面的方法都没有找到也会抛异常。
  • 注意:上面的赋值取值方法以及成员变量可以是私有的,依然可以访问,即KVC是可以访问对象的私有属性的。
//.m文件
#import "Person.h"
@interface Person(){
    @private
    int _age;
    int _isAge;
    int age;
    int isAge;
}

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        Person * p = [[Person alloc]init];
        [p setValue:@18 forKey:@"age"];
        NSLog(@"%@",[p valueForKey:@"age"]);
        
    }
    return 0;
}
kvc访问私有属性.png

你可能感兴趣的:(iOS底层原理之`OC语法`(二.KVC和KVO))