zoukankan      html  css  js  c++  java
  • iOS开发--KVC&KVO

         KVC和KVO这两个词看起来很唬人的样子,很多人一开始接触的时候都不知道这是什么鬼,而且掌握了后又容易忘。所以在这里简单做个笔记,以备不时之需。下面分别介绍一下KVC和KVO的使用方法。

    1.KVC

        KVC是Key-Value Coding的缩写,是键值编码的意思,它是一种可以直接通过字符串的名字(key)来访问类属性(实例变量)的机制。主要、、常用的是setValue:forKey:以及setValue:forKeyPath:这两个方法。

       (1)先来看下setValue:forKey:的用法。建一个测试类Person,头文件里有个年龄属性age。

    1 #import <Foundation/Foundation.h>
    2 
    3 @interface Person : NSObject
    4 
    5 @property (nonatomic, assign) NSInteger age;
    6 
    7 @end

       示例1: 在基类里我们可以直接通过setter方法或者setValue:forKey:方法对Person里的age成员赋值。 

    1 //setter方法赋值
    2 self.person.age = 18;
    3 NSLog(@"我-%ld,是通过setter方法赋予年龄的",self.person.age);
    4 
    5 //setValue:forKey:方法赋值,第一个参数是要设置的值,第二个参数是变量名
    6 [self.person setValue:@(24) forKey:@"age"];
    7 NSLog(@"我-%ld,是通过setValueForKey方法赋予年龄的",self.person.age);

       运行结果如下:

    1 2016-03-14 10:07:15.135 KVC[815:66605] 我-18,是通过setter方法赋予年龄的
    2 2016-03-14 10:07:15.135 KVC[815:66605] 我-24,是通过setValueForKey方法赋予年龄的

       示例2:我们也可通过getter方法或者valueForKey:方法来获取变量的值.  

    1  self.person.age = 30;
    2  NSLog(@"我-%ld,是通过setter方法获取年龄的",self.person.age);
    3  NSLog(@"我-%@,是通过setter方法获取年龄的",[self.person valueForKey:@"age"]);

       运行结果如下: 

    1 2016-03-14 10:18:20.098 KVC[869:133820] 我-30,是通过setter方法获取年龄的
    2 2016-03-14 10:18:20.099 KVC[869:133820] 我-30,是通过valueForKey:方法获取年龄的

       示例3:对于Person里的私有成员属性,我们只能通过setValue:forKey:和valueForKey:方法来进行赋值和获取。

       譬如在Person.m文件里声明一个name属性。 

     1 @implementation Person
     2 {
     3     NSString *_name;
     4 }
     5 
     6 -(instancetype)init{
     7 
     8     self = [super init];
     9     if(self){
    10     
    11         _name = @"小明";
    12     }
    13     
    14     return self;
    15 }

       然后我们对其进行赋值或获值。  

    1 //先通过valueForKey:方法获取name的值
    2 NSLog(@"我原名叫-%@",[self.person valueForKey:@"name"]);
    3 //再通过setValue:forKey:方法对其赋值
    4 [self.person setValue:@"小王" forKey:@"name"];
    5 NSLog(@"我现在叫-%@,是通过setValue:forKey:方法重命名的",[self.person valueForKey:@"name"]);

       运行结果如下: 

    1 2016-03-14 10:36:55.067 KVC[941:197346] 我原名叫-小明
    2 2016-03-14 10:36:55.067 KVC[941:197346] 我现在叫-小王,是通过setValue:forKey:方法重命名的

       (2)再来看下setValue:forKeyPath:的用法。这是通过键路径来给变量赋值,可以简单理解为给类的成员的成员赋值。

            譬如说,我们在上面的基础上再建一个类Address,里面有一个address的成员属性,然后在Preson里面声明。 

     1 #import <Foundation/Foundation.h>
     2 
     3 @interface Address : NSObject
     4 
     5 @property (nonatomic, strong) NSString *address;
     6 
     7 @end
     8 
     9 
    10 #import <Foundation/Foundation.h>
    11 @class Address;
    12 
    13 @interface Person : NSObject
    14 
    15 @property (nonatomic, assign) NSInteger age;
    16 @property (nonatomic, strong) Address *addr;
    17 
    18 @end

         示例1.给Person的Address成员里的address属性进行赋值。

    1 //通过setter方法赋值
    2 self.person.addr.address = @"老家";
    3  NSLog(@"我之前在-%@,是通过setter方法得到地址的",self.person.add.address);
    4  //通过setValue:forKeyPath:进行赋值
    5 [self.person setValue:@"深圳" forKeyPath:@"addr.address"];
    6  NSLog(@"我现在在-%@,是通过setValue:forKeyPath:方法得到地址的",self.person.addr.address);

         运行结果如下:

    1 2016-03-14 10:56:59.127 KVC[1046:317724] 我之前在-老家,是通过setter方法得到地址的
    2 2016-03-14 10:56:59.128 KVC[1046:317724] 我现在在-深圳,是通过setValue:forKeyPath:方法得到地址的

         示例2:通过getter或者valueForKeyPath:获取address的值。  

    1 self.person.addr.address = @"北京";
    2 NSLog(@"我将要去-%@,通过getter方法得知目的地的",self.person.addr.address);
    3 NSLog(@"我将要去-%@,通过valueForKeyPath:方法得知目的地的",[self.person valueForKeyPath:@"addr.address"]);

         运行结果如下: 

    1 2016-03-14 11:04:27.547 KVC[1102:348596] 我将要去-北京,通过getter方法得知目的地的
    2 2016-03-14 11:04:27.548 KVC[1102:348596] 我将要去-北京,通过valueForKeyPath:方法得知目的地的

         对于私有成员属性,情况和上面类似,就不做过多赘述。

         注:当通过key来访问类成员属性的时候,会查找这个类里与key相匹配的实例变量(_key, key, _isKey, isKey)。比如说下面这句代码:  

    1 [self.person setValue:@"小王" forKey:@"name"];

    会匹配_name、name、_isName、isName这四个实例变量,当同时存在时,优先级为:_name>_isName>name>isName;当这四个实例变量都不存在时,通过valueForKey:或者valueForKeyPath: 这两个方法获取变量程序会报错。      

         这里对于KVC的简单介绍就完结了,如果需要了解setValue:forKey方法的实现原理,可以参考这篇文章:http://www.jianshu.com/p/d54af904967b

    2.KVO

         KVO是Key-Value Observing的缩写,翻译为键值观察,是一种监听机制,当指定的对象的属性被修改后,则观察者就会接受到通知。

         KVO的使用步骤:给对象添加指定路径的观察者,设置观察者的监听回调,移除观察者

         (1)在上面的基础上,设置Person为观察者,观察其成员addr的address属性的变化。 

     1 -(instancetype)init{
     2 
     3     self = [super init];
     4     if(self){
     5     
     6          _addr = [[Address alloc] init];
     7         //给_addr添加观察者为当前类self,观察其属性address的变化
     8         //若address属性发生变化,则通过回调方法observeValueForKeyPath:方法告知
     9         //context是可以传给回调方法的内容
    10         [_addr addObserver:self forKeyPath:@"address" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
    11     }
    12     
    13     return self;
    14 }

         (2)重写回调方法,输出addr的address属性改变前后的值。 

    1 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
    2 
    3     NSLog(@"------ 分隔线 ------");
    4     NSLog(@"原来的地址是:%@",change[NSKeyValueChangeOldKey]);
    5     NSLog(@"现在的地址是:%@",change[NSKeyValueChangeNewKey]);
    6 }

         (3)移除观察者。

    1 -(void)dealloc{
    2 
    3     [_addr removeObserver:self forKeyPath:@"address"];
    4 }

          然后我们改变两次addr的address属性。

    1 self.person.addr.address = @"老家";
    2 [self.person setValue:@"深圳" forKeyPath:@"addr.address"];

          运行结果如下:  

    1 2016-03-14 11:22:44.370 KVC[1199:448041] ------ 分隔线 ------
    2 2016-03-14 11:22:44.371 KVC[1199:448041] 原来的地址是:<null>
    3 2016-03-14 11:22:44.371 KVC[1199:448041] 现在的地址是:老家
    4 2016-03-14 11:22:44.371 KVC[1199:448041] ------ 分隔线 ------
    5 2016-03-14 11:22:44.371 KVC[1199:448041] 原来的地址是:老家
    6 2016-03-14 11:22:44.371 KVC[1199:448041] 现在的地址是:深圳

          这样KVO的简单流程就完成了。

  • 相关阅读:
    【leetcode_easy】589. N-ary Tree Preorder Traversal
    【linux基础】Ubuntu下的终端多标签切换快捷键
    车道线检测github集锦
    [c++]struct timeval
    [opencv] copyTo函数的使用方法
    [c++]C++关键字之friend
    【动手学深度学习】Jupyter notebook中 import mxnet出错
    【opencv】split
    【leetcode_easy】581. Shortest Unsorted Continuous Subarray
    第1课 学习Lua的意义
  • 原文地址:https://www.cnblogs.com/AnLoveHuan/p/5259109.html
Copyright © 2011-2022 走看看