KVC详解

作者: 雪域红鹰 | 来源:发表于2020-04-15 22:16 被阅读0次

kvc是什么?

kvc(Key-value-coding)键值编码,一个非正式的协议.提供一种机制间接访问对象的属性.而不是通过调用setter,getter方法获取.就是说在ios开发中,可以允许开发者通过key名直接访问对象的属性,或者给对象的属性赋值.而不需要调用明确存取方法.

kvc有什么作用?

kvc的作用就是可以给对象的私有变量进行赋值.即在运行时动态的访问或修改对象的属性.

kvc的赋值和取值

kvc中定义都是对NSObject的扩展类实现的,oc中的kvc最基本的几个方法:

  • (nullable id)valueForKey:(NSString *)key; //直接通过Key来取值
  • (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
  • (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来 取值
  • (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过 KeyPath来设值

NSKeyValueCoding类别中其他的一些方法

  • (BOOL)accessInstanceVariablesDirectly;
    //默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索
  • (BOOL)validateValue:(inout id __nullable * _nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
    //KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因.
  • (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;
    //这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回.
  • (nullable id)valueForUndefinedKey:(NSString *)key;
    //如果Key不存在,且没有KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常
  • (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
    //和上一个方法一样,但这个方法是设值.
  • (void)setNilValueForKey:(NSString *)key;
    //如果你在SetValue方法时面给Value传nil,则会调用这个方法
  • (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
    //输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典.

kvc设值

设值是通过setValue:forKey:的默认实现,给定输入参数value和key。试图在接收调用对象的内部,设置属性名为key的value,通过下面的步骤
1.查找set<Key>、_ set<Key>命名的setter,按照这个顺序,如果找到的话,调用这个方法并将值传进去(根据需要进行对象转换).
2.如果没有发现一个简单的setter,但是accessInstanceVariablesDirectly类属性返回YES,则查找一个命名规则为__<key>、_is<Key>、<key>、is<Key>的实例变量.根据这个顺序,如果发现则将value赋值给实例变量.
3.如果没有发现setter或实例变量,则调用setValue:forUndefinedKey:方法,并默认提出一个异常,但是一个NSObject的子类可以提出合适的行为
eg:

   @interface Person : NSObject{
      NSString *_name;
   }  
  @end

//创建对象
Person *p = [[Person alloc] init];
//通过kvc赋值
[p setValue:@"小明" forKey:@"name"];
//通过kvc取值
NSLog(@"p的名字是%@",[p valueForKey:@"name"]);

//打印结果
//p的名字是小明

在以上代码中添加,accessInstanceVariablesDirectly为NO,结果如下.

 @implementation Person
 +(BOOL)accessInstanceVariablesDirectly{
     return NO;
 }
 -(id)valueForUndefinedKey:(NSString *)key{
   NSLog(@"出现异常,此key不存在%@",key);
   return nil;
 }
 -setValue:(id)value forUndefinedKey:(NSString *)key{
     NSLog(@"设置值时出现异常,该key不存在%@",key);
 }
 @end
  //打印结果
  设置值时出现异常,该key不存在name
  出现异常,此key不存在name
  p的名字是(null)

如果accessInstanceVariablesDirectly为YES,打印结果和首次显示一样.这里不在重复结果.在修改成员变量名为_name,_isName,name,isName时都会打印出正确的结果.所以简单来说就是*如果没有找到set<key>,会按照_key,_isKey,key,isKey的顺序搜索成员并进行赋值操作.

kvc取值

取值是同valueForKey:来实现的,给定一个key当做输入参数,下面的步骤,在这个接收valueForKey:方法调用的类内部进行操作.
1.通过getter方法搜索实例,例如get<Key>, <key>, is<Key>, _ <key>的拼接方案。按照这个顺序,如果发现符合的方法,就调用对应的方法并拿着结果
2.如果没有找到上面getter方法,kvc会查找countOf<Key>
objectIn<Key>AtIndex、<key>AtIndexes格式的方法.如果这个三个方法倍找到,那么返回一个可以响应NSArray所有方法的代理集合(NSKeyValueArray,是NSArray的子类),给这个代理集合发NSSet的消息,就会以这个几个方法组合的形式调用
3.如果上面的方法名没有找到,那么会同时查找countOf<Key>,enumeratorOf<Key>,memberOf<Key>格式的方法,如果这三个方式都找到,那么返回一个可以响应NSSet所有的方法的代理集合,给这个代理集合发NSSet的消息,就会以这个几个方法组合的形式调用
4.如果还没有找到,再检查类方法 accessInstanceVariablesDirectly是否为YES,如果是YES,会按_ <key>、_is<key>、<key>、is<key>的顺序搜索成员变量名,如果发现将value赋值给实例变量.如果accessInstanceVariablesDirectly为NO,那么会直接调用forUndefinedKey方法,抛出异常
eg:

    @implementation Person
     -(NSInteger)getAge{
      return 10;
    }
   @end

//创建对象
Person *p = [[Person alloc] init];
//通过kvc取值
NSLog(@"p的年龄是%@",[p valueForKey:@"age"]);

//打印结果
//p的年龄是10

从上面的代码可以看到,找到getAge方法,就获取到age的值.
分别把getAge方法名改为age、_age、isAge都可以获取到正确的值.上面代码充分说明了kvc在调用valueforkey是搜索key的机制

kvc中keyPath的使用

在开发过程中,一个类的成员变量有可能是自定义类或者其他的复杂数据类型,那么可以使用kvc获取该属性.然后再用kvc来获取这个自定义类的属性.但是这个比较繁琐,所以,kvc提供一个解决方案,那就是键路径keypath

  • (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来
    取值
  • (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过
    KeyPath来设值

eg:

@interface Person : NSObject{ 
  NSString *_name;
}
@end

@interface SubPerson : NSObject{
    Person *_person;
}
@end

//创建对象Person
Person *p = [[Person alloc] init];
//创建对象SubPerson
SubPerson *subp = [[SubPerson alloc] init];
//通过kvc设置person 值
[subp setValue:p forKey:@"person"];

//通过kvc设值person的给name设值
[subp setValue:@"小花" forKeyPath:@"person.name"];
//通过kvc取值
NSLog(@"SubPerson的person名字是%@",[p valueForKey:@"name"]);

//打印结果
//SubPerson的person名字是小花

从上面例子可以看出我们成功的使用了keypath设置person的name属性值.

kvc异常处理

kvc中最常见的异常就是不小心使用了错误的key,或者设置值不小心传递了nil值.kvc中有专门的方法来处理这些异常

kvc处理nil异常

kvc中通常情况下是不能传递nil的,如果不小心传递了nil,kvc会调用setNilValueForkey方法,这个方法默认是抛出异常.
eg:

@interface Person : NSObject{
    NSInteger age;
}
@end

//创建对象Person
Person *p = [[Person alloc] init];
//通过kvc设置age 值
[p setValue:nil forKey:@"age"];

//通过kvc取值
NSLog(@"person的名字是%@",[p valueForKey:@"age"]);

//打印结果
//    不能将age设置为nil
//    person的名字是0

kvc处理Undefinekey异常

通常kvc不允许调用一个不存在的key赋值,不然会报错forUndefinekey发生崩溃,所以重写forUndefinekey就可以避免崩溃
eg:

@interface Person : NSObject{

}
@end

//创建对象Person
Person *p = [[Person alloc] init];
//通过kvc设置person 值
[p setValue:nil forKey:@"age"];

//通过kvc取值
NSLog(@"person的名字是%@",[p valueForKey:@"age"]);

//打印结果
//    设置值时出现异常,该key不存在age
//    出现异常,此key不存在age
//    person的名字是(null)

KVC使用

KVC在iOS开发中是绝不可少的利器,这种基于运行时的编程方式极大地提高了灵活性,简化了代码,甚至实现很多难以想像的功能,KVC也是许多iOS开发黑魔法的基础。
下面列举iOS开发中KVC的使用场景.
1.动态地取值和设值
利用KVC动态的取值和设值是最基本的用途了.
2.用KVC来访问和修改私有变量
对于类里的私有属性,Objective-C是无法直接访问的,但是KVC是可以的.
3.Model和字典转换
使用kvc和objc的runtime组合可以实现mode和字典的转换(YYModel)
4.访问和修改这些控件的样式
而KVC在大多数情况可下可以解决这个问题。最常用的就是个性化UITextField中的placeHolderText了.

相关文章

  • iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

    iOS开发技巧系列---详解KVC(我告诉你KVC的一切) iOS开发技巧系列---详解KVC(我告诉你KVC的一切)

  • iOS日记15-KVC

    1.iOS开发技巧系列---详解KVC 2.漫谈 KVC 与 KVO 3.KVC/KVO原理详解及编程指南 关键点...

  • iOS 关于KVC的一些总结

    本文参考: KVC官方文档 KVC原理剖析 iOS KVC详解 KVC 简介 KVC全称是Key Value Co...

  • iOS 关于KVC的一些总结(转)

    原文:iOS 关于KVC的一些总结 本文参考: KVC官方文档 KVC原理剖析 iOS KVC详解 KVC 简介 ...

  • iOS Objective-C KVC 详解

    iOS Objective-C KVC 详解 1. KVC简介 KVC 全称Key Value Coding,是苹...

  • iOS-- KVC

    推荐一篇超好的KVC详解博客:《详解KVC,我来告诉你KVC的一切》,看完之后顿时觉得自己没啥写的, 分享一下。

  • OC--KVC

    参考:iOS开发技巧系列---详解KVC(我告诉你KVC的一切)KVC原理剖析 NSObject(NSKeyVal...

  • 详解KVO,KVC

    转自小菜鸟dxb => 详解KVO,KVC 1、KVC,即是指 NSKeyValueCoding,一个非正式的Pr...

  • KVC 和 KVO详解

    KVC 详解 KVC : 键值编码(Key-Value Coding),它是一种通过key值访问类属性的机制,而不...

  • KVC详解

    KVC(Key-valueCoding) KVC键值编码,是对NSObjcet的扩展,分类名为:NSKeyValu...

网友评论

      本文标题:KVC详解

      本文链接:https://www.haomeiwen.com/subject/ayydvhtx.html