iOS-Developer-OCiOS - Developer - OC 进阶大全

Object-C中KVC

2019-08-01  本文已影响1人  zwwuchn

什么是KVC

KVC(Key-value coding)键值编码。iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值。这样可以免去我们调用getter和setter方法,从而简化我们的代码,也可以用来修改系统控件内部属性

KVC最为重要的四个方法
- (void)setValue:(nullable id)value forKey:(NSString *)key;  //通过Key来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通过KeyPath来设值
- (nullable id)valueForKey:(NSString *)key;                  //直接通过Key来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;  

KVC使用

@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@end

@interface Person()
@end
----代码-----

Person *per = [[Person alloc] init];
        
[per setValue:@"jack" forKey:@"name"];
        
NSString *name = [per valueForKey:@"name"];
        
NSLog(@"%@", name);
打印结果:
jack

系统内部做了什么

这里我们要使用这个分类DLIntrospection
(lldb) po [object_getClass(per) instanceMethods]
<__NSArrayI 0x1005715c0>(
- (void).cxx_destruct,
- (id)name,
- (void)setName:(id)arg0 
)
从上面的调试中,可以看出,使用-setValue: forKey:方法,内部调用了成员属性setter,get方法

我们来验证一下是否真的调用了成员属性setter,get方法

在Person.m文件重写setter方法
- (NSString *)name {
    NSLog(@"name");
    return _name;
}
- (void)setName:(NSString *)name {
    
    NSLog(@"setName");
}
打印结果:
setName
name
所以验证了我们刚才打印出来的方法

KVC" 真 "调用流程

①.调用setValue:forKey:
> 按照顺序查找setKey、_setKey方法

验证一下:
1.1 删除 @property (nonatomic, copy) NSString *name;
1.2 在Person.m文件重写setKey、_setKey方法
- (void)setName:(NSString *)name {

    NSLog(@"setName");
}
- (void)_setName:(NSString *)name {

    NSLog(@"_setName");
}
打印结果:
setName

1.3 隐藏 - (void)setName:(NSString *)name 方法
打印结果:
_setName
②.如果没有找到方法
> 查看accessInstanceVariablesDirectly方法返回值

2.1 默认返回YES
2.2 如果返回NO,会抛出异常NSUnknownKeyException
③.accessInstanceVariablesDirectly方法返回YES
> 会按照_key、_isKey、key、isKey顺序查找成员变量

验证一下
3.1 在Person.m文件生成如下变量
@interface Person()
{
    @public
    NSString *_name;
    NSString *_isName;
    NSString *name;
    NSString *isName;
}
@end
④.如果没有找到_key、_isKey、key、isKey成员变量,就会抛出异常,如下图
图片.png

valueForKey: 的原理

①.调用valueForKey:
> 按照顺序查找getKey、key、isKey、_key方法

验证一下:
1.1 删除 @property (nonatomic, copy) NSString *name;
1.2 在Person.m文件重写getKey、key、isKey、_key方法
- (NSString *)getName {

    return @"张三";
}

- (NSString *)name {
    return @"李四";
}

- (NSString *)isName {
    return @"王五";
}

- (NSString *)_name {

    return @"小六";
}
分别注释打印结果:
张三
----
李四
----
王五
----
小六
②.如果没有找到方法
> 查看accessInstanceVariablesDirectly方法返回值

2.1 默认返回YES
2.2 如果返回NO,会抛出异常NSUnknownKeyException
③.accessInstanceVariablesDirectly方法返回YES
> 会按照_key、_isKey、key、isKey顺序查找成员变量

验证一下
3.1 在Person.m文件生成如下变量
@interface Person()
{
    @public
    NSString *_name;
    NSString *_isName;
    NSString *name;
    NSString *isName;
}
@end
④.如果没有找到_key、_isKey、key、isKey成员变量,就会抛出异常,如下图
图片.png
上一篇下一篇

猜你喜欢

热点阅读