如果你从事iOS开发,
对于KVO肯定不陌生.
今天写了这篇文章,
让我们进一步了解KVO,
我们从下图几个部分了解KVO,
如果你看了这篇文章,
会颠覆你对KVO的认知,
原来你了解过得KVO只是一部分.
1.什么是KVO?
KVO(Key Value Observing, 键值观察)是Objective-C对观察者模式的实现,每次当被观察对象的某个属性值发生改变时,注册的观察者便能获得通知。
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:638302184,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 与2800+iOS开发者一起交流学习成长!
2.KVO的使用
这里我们结合代码了解KVO,
单纯的文字描述已经没有发言权.
- 案例一:
1.1我们先创建一个person类
#import
@interface Person : NSObject{
@property(nonatomic,copy)NSString *name;
@end
#import "Person.h"
@implementation Person
@end
并为person添加属性name
此时,我们已经创建好了person类
1.2接着,我们在viewDidLoad方法中创建Person对象
//方便引用
@property(nonatomic,strong)Person *p;
Person *p = [[Person alloc]init];
//引用
_p = p;
p指针在哪个地方? p指针指向引用数据类型,对象在堆区,指针在栈区.
1.3接着我们在ViewDidLoad方法中添加观察
[图片上传失败...(image-532afe-1577458318977)]
[p addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:nil];
1.4使用touchesBegan时间,改变属性值,以方便进行观察.
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
static int a;
_p.name = [NSString stringWithFormat:@"%d",a++];
}
1.5此时我们运行会不会有结果呢?
答案是我们点击屏幕的时候,程序会崩溃.因为我们这里没有去响应.
我们要添加响应的方法
//响应方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
//观察者观察name的变化,当点击屏幕,改变name的值,chang就会捕获新值.
NSLog(@"%@",change);
}
1.6,此时你运行起来点屏幕几下.控制台就会有输出了.
2018-03-31 18:38:54.319824+0800 001--kvo使用[2725:50940] {
kind = 1;
new = 0;
}
案例一,创建了基本简答的KVO.
- 案例二
如果我们改变了name的属性,observe回调就来了,这就是自动触发.
还有只用,变化了不一定每一次都通知,平常开发需求也会遇到.
如果满足了某一个条件的时候,我们来通知一下.
2.1我们在person中添加一个方法
+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
//手动触发
return NO;
//自动触发
// return YES;
}
2.2这个时候,我们回到ViewController中,对,touchBegan方法进行修改,就可以完成手动触发.
static int a;
//手动触发
//即将改变
[_p willChangeValueForKey:@"name"]
_p.name = [NSString stringWithFormat:@"%d",a++];
// 改变完成
[_p didChangeValueForKey:@"name"];
```
2.3如果我们想满足一个条件后,进行属性观察.
我们就要在 automaticallyNotifiesObserversForKey:(NSString *)key
通过判断key来进行手动触发或者自动触发.
比如,我们判断是name的时候,我们手动触发
//手动触发
if([key isEqualToString:@"name"]){
return NO;
}
return YES;
```
案例二,手动触发,自动触发
- 案例三
我们创建一个dog类,.我们想观察person中的dog属性的变化,我们可以这样注册.
3.1首先,我们先创建dog类
#import
@interface Dog : NSObject
@property(nonatomic,assign)int age;
@end
#import "Dog.h"
@implementation Dog
@end
3.2我们在person中加入
@property(nonatomic,strong)Dog *dog;
3.3对dog进行初始化
-(instancetype)init{
if(self=[super init]){
_dog=[[Dog alloc]init];
}
return self;
}
3.4我们添加观察者
[p addObserver:self forKeyPath:@"dog.age" options:(NSKeyValueObservingOptionNew) context:nil];
3.5在点击事件中,改变age的值
_p.dog.age = a++;
我们观察到dog的age值变化
- 案例四:
4.1我们在dog类中加入level
@property(nonatomic,assign)int level;
4.2通过person中的dog属性,我们观察dog中的level和age属性的变化
[p addObserver:self forKeyPath:@"dog.age" options:(NSKeyValueObservingOptionNew) context:nil];
[p addObserver:self forKeyPath:@"dog.level" options:(NSKeyValueObservingOptionNew) context:nil];
4.3在点击事件中,改变age和level
// _p.dog.age = a++;
// _p.dog.level = a++;
4.4运行后,我们就可以看到属性值的变化.
案例四,是不是有些麻烦呢,这种方式我们要写两次
4.KVO观察容器
1.KVO --响应式编程
首先,我们需要添加,订阅,然后有响应的方法
代理是么?其实代理也一样
比如tableView,我们添加代理,就可以使用代理方法,代理方法回调.
比如button时间,其实也是响应式编程,为button添加target,开启方法,方法调用.2.我们在案例六中提到了数组,我们初始化后并没有观察到person中array属性的变化
我们这次就要借助KVC
2.1我们创建person类,加入arr属性
@property(nonatomic,strong)NSMutableArray *arr;
2.2初始化数组
- (instancetype)init
{
self = [super init];
if (self) {
_arr = NSMutableArray.array;
}
return self;
}
2.3在VC中
@property(nonatomic,strong)Person *p;
2.4创建person对象,添加观察者
Person *p = [[Person alloc]init];
_p = p;
[_p addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:nil];
2.5响应方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
NSLog(@"%@",change);
}
2.6touchesBegan中加入
//KVO监听容器方法,需要借助KVC
NSMutableArray *tempArr = [_p mutableArrayValueForKeyPath:@"arr"];
[tempArr addObject:@"123"];
2.7程序跑起来,我们在控制台可以看到
2018-03-31 21:15:13.551030+0800 003-KVO观察容器[3369:118039] {
indexes = "<_NSCachedIndexSet: 0x60400003ff60>[number of indexes: 1 (in 1 ranges), indexes: (0)]";
kind = 2;
new = (
11
)
```
这里的kind是什么意思?
在案例1中输出的kind=1,这里的kind=2.这代表了什么意思?
//set方法,kind=1
NSKeyValueChangeSetting = 1,
//插入
NSKeyValueChangeInsertion = 2,
//删除
NSKeyValueChangeRemoval = 3,
//替换
NSKeyValueChangeReplacement = 4,
有没有颠覆KVO调setter方法,还可以调用insert,remove,replace
这里输出的kind2,说明了插入的数据的时候,观察者也可以观察到属性值的变化.
如果没有深入了解一下KVO,知道了KVO不仅可以调用setter方法,还可以调用插入,删除,代替方法.
### 总结
1.动态创建Person的子类使用
2.子类重写setName
3.动态修改了对象的类型
4.还了解到了,KVO不仅可以调用setter方法,还可以调用插入,删除,代替方法.通过对kvo的进一步了解,我们是很清楚KVO底层运用.
好的,这就是KVO.
这篇文章能帮到您,
请您点个赞