码迷,mamicode.com
首页 > 移动开发 > 详细

iOS开发——实用篇&KVO与KVC详解

时间:2015-07-13 23:58:30      阅读:605      评论:0      收藏:0      [点我收藏+]

标签:

KVO与KVC详解

由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby、Python的动态特性,例如动态类型、动态加载、动态绑定等。今天我们着重介绍ObjC中的键值编码(KVC)、键值监听(KVO)特性:

  1. 键值编码KVC
  2. 键值监听KVO

键值编码KVC

我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象。其实由于ObjC的语言特性,你根部不必进行任何操作就可以进行属性的动态读写,这种方式就是Key Value Coding(简称KVC)。

KVC的操作方法由NSKeyValueCoding协议提供,而NSObject就实现了这个协议,也就是说ObjC中几乎所有的对象都支持KVC操作,常用的KVC操作方法如下:

  • 动态设置: setValue:属性值 forKey:属性名(用于简单路径)setValue:属性值 forKeyPath:属性路径(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性) 
  • 动态读取: valueForKey:属性名 valueForKeyPath:属性名(用于复合路径)

键值监听KVO

我们知道在WPF、Silverlight中都有一种双向绑定机制,如果数据模型修改了之后会立即反映到UI视图上,类似的还有如今比较流行的基于MVVM设计模式的前端框架,例如Knockout.js。其实在ObjC中原生就支持这种机制,它叫做Key Value Observing(简称KVO)。KVO其实是一种观察者模式,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,不过幸运的是NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。

在ObjC中使用KVO操作常用的方法如下:

  • 注册指定Key路径的监听器: addObserver: forKeyPath: options:  context:
  • 删除指定Key路径的监听器: removeObserver: forKeyPathremoveObserver: forKeyPath: context:
  • 回调监听: observeValueForKeyPath: ofObject: change: context:

KVO的使用步骤也比较简单:

  1. 通过addObserver: forKeyPath: options: context:为被监听对象(它通常是数据模型)注册监听器 
  2. 重写监听器的observeValueForKeyPath: ofObject: change: context:方法

/*********************************KVC/KVO*******************************************/

KVC

kvc在实际开发中使用最多的地方一般有两个

  • 字典转模型:但是这个有一个局限性,如果他的属性也是一个模型的时候不能使用这个方法,或者不能一一对应的时候
  • 通过属性键设置对应属性的值

字典转模型:

 1 #pragma mark 简单字典转模型
 2         NSDictionary *dict = @{
 3                                @"name"  : @"jack",
 4                                @"money" : @"20.7",
 5                                };
 6     
 7         [p setValuesForKeysWithDictionary:dict];
 8         NSLog(@"name = %@, money = %f", p.name, p.money);
 9     
10 #pragma mark 复杂模型
11     NSDictionary *dict = @{
12                            @"name"  : @"jack",
13                            @"money" : @"20.7",
14                            @"dog" : @{
15                                    @"name" : @"wangcai",
16                                    @"price" : @"10.8"
17                                    },
18                            @"books" : @[
19                                    @{
20                                        @"name" : @"5分钟突破iOS开发",
21                                        @"price" : @"19.8"
22                                        },
23                                    @{
24                                        @"name" : @"3分钟突破iOS开发",
25                                        @"price" : @"24.8"
26                                        },
27                                    @{
28                                        @"name" : @"1分钟突破iOS开发",
29                                        @"price" : @"29.8"
30                                        }
31                                    ]
32                            };
33     [p setValuesForKeysWithDictionary:dict];
34     NSLog(@"%@", p);
35 }

 

设置属性的值:

 1 #pragma mark 单个值
 2         p.name = @"lnj";
 3         p.money = 99.8;
 4     
 5         [p setValue:@"lnj" forKey:@"name"];
 6         [p setValue:@(99.8) forKey:@"money"];
 7         NSLog(@"name = %@, money = %f", p.name, p.money);
 8     
 9 #pragma mark 多层赋值
10     
11         p.dog = [XMGDog new];
12         p.dog.name = @"wangcai";
13         p.dog.price = 998;
14     
15         [p.dog setValue:@"wangcai" forKey:@"name"];
16         [p.dog setValue:@(998) forKey:@"price"];
17     
18         [p setValue:@"wangcai" forKeyPath:@"dog.name"];
19         [p setValue:@(998) forKeyPath:@"dog.price"];
20         NSLog(@"name = %@, price = %f", p.dog.name, p.dog.price);
21     
22 #pragma mark 私有属性
23     
24         [p setValue:@"lnj" forKeyPath:@"_name"];
25         [p setValue:@(30) forKeyPath:@"_age"];
26     
27         NSLog(@"name = %@", p.name);
28         [p say];

 

 

KVO

1:创建一个对象

 1 iCocos *stu = [[iCocos alloc] init]; 2  

2:注册指定Key路径的监听器,并且修改相应的属性

1 [stu addObserver:self forKeyPath:@"score" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
2     
3     stu.score = 90;
4     
5     stu.score = 100;

3:删除指定Key路径的监听器

1 #warning 注意只有调用set方法修改才能监听到 2 内部实现原理是: 系统会自动给我们生成一个子类, 然后重写子类的set方法, 在set方法中通知监听
3     stu->_score = 250;
4     [stu removeObserver:self forKeyPath:@"score"];

 

4:回调监听

1 - (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context
2 {
3     NSLog(@"keyPath = %@, obj = %@, change = %@, context = %@", keyPath, object, change, context);
4 }

 

KVO内部实现机制:

 系统会自动给我们生成一个子类, 然后重写子类的set方法, 在set方法中通知监听

iOS开发——实用篇&KVO与KVC详解

标签:

原文地址:http://www.cnblogs.com/iCocos/p/4644079.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!