IOS开发 - KVC和KVO的使用

1,KVC

1,集合运算符(Collection Operators)

集合运算符是一个特殊的Key Path,可以作为参数传递给valueForKeyPath:方法, 注意只能是这个方法 ,如果传给了valueForKey:方法保证你程序崩溃。
运算符是一个以@开头的特殊字符串,格式如下图所示:


①简单集合运算符 
简单集合运算符共有@avg,@count,@max,@min,@sum5种,都表示啥不用我说了吧,  目前还不支持自定义 。 
有一个集合类的对象:transactions,它存储了一个个的Transaction类的实例,该类有三个属性:payee,amount,date。下面以此为例说明如何使用这些运算符:
要获取amount的平均值可以这样:
NSNumber *transactionAverage = [transactions valueForKeyPath:@"@avg.amount"];
要获取transactions集合中元素数目可以这样:
NSNumber *numberOfTransactions = [transactions valueForKeyPath:@"@count"];
需要之处的是,@count是这些集合运算符中比较特殊的一个,因为它没有右路经,原因很容易理解。
②对象运算符
比集合运算符稍微复杂,能以数组的方式返回指定的内容,一共有两种:
@distinctUnionOfObjects
@unionOfObjects
它们的返回值都是NSArray,区别是前者返回的元素都是唯一的,是去重以后的结果;后者返回的元素是全集。
用法如下:
NSArray *payees = [transactions valueForKeyPath:@"@distinctUnionOfObjects.payee"];
NSArray *payees = [transactions valueForKeyPath:@"@unionOfObjects.payee"];
前者会将收款人的姓名去除重复的以后返回,后者直接返回所有收款人的姓名。
③Array和Set操作符
这种情况更复杂了,说的是集合中包含集合的情况,我们执行了如下的一段代码:
// Create the array that contains additional arrays.
self.arrayOfTransactionsArray = [NSMutableArray array];
 
// Add the array of objects used in the above examples.
[arrayOfTransactionsArray addObject:transactions];
 
// Add a second array of objects; this array contains alternate values.
[arrayOfTransactionsArrays addObject:moreTransactions];
得到了一个包含集合的集合:arrayOfTransactionsArray
这时如果我们想操作 arrayOfTransactionsArray中包含的集合中的元素时,可以使用如下三个运算符:
@distinctUnionOfArrays
@unionOfArrays
@distinctUnionOfSets
前两个针对的集合是Arrays,后一个针对的集合是Sets。 因为Sets中的元素本身就是唯一的,所以没有对应的@unionOfSets运算符。
它们的用法举例如下:
NSArray *payees = [arrayOfTransactionsArrays valueForKeyPath:@"@unionOfArrays.payee"];


2,KVO

KVO的是Key Value Observe的缩写,中文是键值观察。这是一个典型的观察者模式,观察者在键值改变时会得到通知。iOS中有个Notification的机制,也可以获得通知,但这个机制需要有个Center,相比之下KVO更加简洁而直接。

KVO的使用也很简单,就是简单的3步。
1).注册需要观察的对象的属性addObserver:forKeyPath:options:context:
2).实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用
3).取消注册观察removeObserver:forKeyPath:context:

测试发现,只要属性值发生了变化,即使变化前和变化后的数值,地址完全一样,也会触发监测事件;不管是类的属性,还是写在大括号中的私有变量,都可以通过kvc/kvo来修改个监测值的变化。

1、添加监听对象
我们使用addObserver方法给孩子添加监听对象
第一个参数:监听者,这里是Nure,所以可以直接传递self
第二个参数:监听对象的属性名
第三个参数:监听这个属性的状态:这里可以使用|进行多种组合操作,属性的新值和旧值
第四个参数:传递内容给监听方法<pre name="code" class="objc">//观察小孩的hapyValue  
//使用KVO为_children对象添加一个观察者,用于观察监听hapyValue属性值是否被修改  
[_children addObserver:self forKeyPath:@"hapyValue" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:@"context"];  
  
//观察小孩的hurryValue  
[_children addObserver:self forKeyPath:@"hurryValue" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:@"context"];  
2、监听方法
//触发方法  
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context{  
    NSLog(@"%@",change);  
    //通过打印change,我们可以看到对应的key  
      
    //通过keyPath来判断不同属性的观察者  
    if([keyPath isEqualToString:@"hapyValue"]){  
        //这里change中有old和new的值是因为我们在调用addObserver方法时,用到了  
        //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;想要哪一个就用哪一个  
        //[change objectForKey:@"old"]是修改前的值  
        NSNumber *hapyValue = [change objectForKey:@"new"];//修改之后的最新值  
          
        NSInteger *value = [hapyValue integerValue];  
          
        if(value < 90){  
            //do something...  
        }  
    }else if([keyPath isEqualToString:@"hurryValue"]){  
        //这里change中有old和new的值是因为我们在调用addObserver方法时,用到了  
        //NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;想要哪一个就用哪一个  
        //[change objectForKey:@"old"]是修改前的值  
        NSNumber *hurryValue = [change objectForKey:@"new"];//修改之后的最新值  
          
        NSInteger *value = [hurryValue integerValue];  
          
        if(value < 90){  
            //do something...  
        }  
    }  
      
    NSLog(@"%@",context);//打印的就是addObserver方法的context参数  
      
      
      
    //使用KVC去修改属性的值,也会触发事件  
}  
这个方法的参数:
第一个参数:键值路径
第二个参数:监听对象
第三个参数:变化的值
第四个参数:传递的内容
我们看到代码中有一个特殊的参数:第三个参数:NSDirctionary类型的
他们就是分别代表这个属性值变化的前后值,同时他们的得到也和之前我们添加监听对象时设置的第三个参数有关:
NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld
那个地方设置了几种状态,这里的NSDirctionary中就会有几个键值对

3、销毁方法
这个并不属于KVO的内容了,只是在这里用到了就顺便说一下
[objc] view plaincopy在CODE上查看代码片派生到我的代码片
- (void)dealloc{  
      
    //移除观察者  
    [_children removeObserver:self forKeyPath:@"hapyValue"];  
    [_children removeObserver:self forKeyPath:@"hurryValue"];  
      
}  

 


我的测试代码

- (instancetype)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        _model = [[Model alloc] init];
        _model.name = @"name";
        _model.age = 13;
        
        [_model addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
        [_model addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
        
    }
    return self;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    NSString *new = [change objectForKey:@"new"];
    NSString *old = [change objectForKey:@"old"];
    
    NSLog(@"keyPath = %@   change = old : %@   new : %@", keyPath, old, new);
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSInteger value = [[_model valueForKey:@"age"] integerValue];
    [_model setValue:@(++value) forKey:@"age"];
    [_model setValue:@"sbc" forKey:@"name"];
}

- (void)dealloc
{
    [_model removeObserver:self forKeyPath:@"name"];
    [_model removeObserver:self forKeyPath:@"age"];
}



我的测试代码:

参考:

http://www.tuicool.com/articles/M7vQRj      //

http://blog.csdn.net/jiangwei0910410003/article/details/41912937


  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值