KVC和runtime的巧妙结合

KVC简介

1.按照官方说明
Key-value coding is a mechanism for indirectly accessing an object’s attributes and relationships using string identifiers.
即KVC键值编码是通过使用字符串标识来访问一个对象的属性的一种机制,这种属性也可以是对象的私有变量,下面再说什么是字符串标识
2.一个对象的属性大致分为三种,官方说明


KVC和runtime的巧妙结合_第1张图片
属性的种类

第一种是简单的foundation属性,例如字符串、整型和Boolean型等
第二种是将自定义的类的对象作为自己的属性,如示例中的Person类(一对一关系)
第三种就是集合类,如数组或者字典等(一对多关系)
我们知道,可以通过setter方法来为这些属性赋值,但是官方文档里面提出这样是不灵活的,看图中线段


KVC和runtime的巧妙结合_第2张图片
官方文档

3.看KVC是如何给属性赋值的
首先看KVC能访问属性的范围
KVC和runtime的巧妙结合_第3张图片
官方文档

从官方图例可以看出,通过KVC,一个对象不仅能访问其属性,也能访问其多级属性,也就是属性的属性

再看赋值方法

KVC和runtime的巧妙结合_第4张图片
KVC赋值方法

从官方文档可以看出,KVC给其属性赋值的方式是
[object setValue:value forKey:@"keyName"];
keyName也就是上面所说的string identifiers,且必须是如此形式,keyName要与该对象的变量名保持一致

从线段所指位置可以看出,对象给其多级属性赋值时要用"."语法访问其
[object setValue:value forKeyPath:@"keyName"];

4.KVC赋值方法


KVC和runtime的巧妙结合_第5张图片
KVC赋值方法

值得注意的是,如果string identifiers找不到,程序便会crash,解决方法是重写图例中的setValue:forUndefinedKey:方法

5.KVC取值方法


KVC和runtime的巧妙结合_第6张图片
取值方法

同样,如果string identifiers找不到,程序便会crash,解决方法是重写图例中的valueForUndefinedKey:方法

6.任何对象为何能通过KVC机制来给属性赋值


KVC和runtime的巧妙结合_第7张图片
非正式协议KVC

第一句已经指出,该机制是通过非正式协议来完成的,非正式协议即给NSObject添加一个Category

进入KVC

上面是官方文档对KVC的一些阐述,下面看KVC的一些方法
首先是修改值

setValue:forKey://给其一级成员变量赋值
setValue:forKeyPath://通过键路径给其多级变量赋值
setValue:forUnderfinedKey://如果未找到同名的string identifiers,则重写该方法,否则报错
setNilValueForKey: //value设置为nil时调用,系统默认调用,不会报错

其次是取值

valueForKey: //通过string identifiers取出通过setValue:forKey:所设置的值
valueForKeyPath: //同上
valueForUndefinedKey: //如果未找到同名的string identifiers,则重写该方法,否则报错

KVC访问属性顺序

@property (nonatomic, copy) NSString *name;
{
    NSString *_name;
    NSString *name;
}

KVC通过遍历所有的成员变量,逐个访问,先查找setName,直接调用,给name属性赋值,如果没有setName,继续寻找_name,最后是name,如果重写了

//默认返回YES
+ (BOOL)accessInstanceVariablesDirectly

并且返回NO,那么,如果找不到setName方法会直接调用

setValue:forUnderfinedKey:

KVC与runtime结合

举个例子,我们想要获取某个控件的私有变量,例如获取UISearchBar的_searchField私有变量,继而去更改UISearchBar输入框的样式等,但是通过官方给的API又无法获取,此时runtime就发挥作用了,如果第一种无法获取到,尝试第二种
第一种(父类属性是不会被遍历出来的)

unsigned int count,i;
//runtime获取UISearchBar属性列表
objc_property_t *propertyArray = class_copyPropertyList([UISearchBar class], &count);
NSMutableArray *array = [NSMutableArray array];
for (i = 0; i < count; i++) {
      objc_property_t property = propertyArray[i];
      NSString *proKey = [NSString stringWithCString:property_getName(property) encoding:NSUTF8StringEncoding];
      [array addObject:proKey];
 }
 NSLog(@"%@",array);
 free(propertyArray);//c语言释放内存函数

第二种

unsigned int count,i;
Ivar *propertyArray = class_copyIvarList([UISearchBar class], &count);
NSMutableArray *array = [NSMutableArray array];
for (i = 0; i < count; i++) {
       Ivar property = propertyArray[i];
      NSString *proKey = [NSString stringWithCString:ivar_getName(property) encoding:NSUTF8StringEncoding];
      [array addObject:proKey];
 }
 NSLog(@"%@",array);
 free(propertyArray);

通过打印结果,第二种方式获取到了_searchField
实际操作时是要结合UI效果调试的,比如更改UISearchBar的输入框背景色,看了UISearchBar的结构,内部包含了一个UITextField,一开始肯定不知道该UITextField就是_searchField,在获取到UISearchBar属性列表后,是要慢慢调试的,获取到该属性之后就可以使用KVC赋值了

在xib中也可以使用runtime和KVC更改控件UI

KVC和runtime的巧妙结合_第8张图片
xib runtime使用

点击+号,一看便知怎么用了

你可能感兴趣的:(KVC和runtime的巧妙结合)