博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
KVC和KVO
阅读量:6656 次
发布时间:2019-06-25

本文共 5010 字,大约阅读时间需要 16 分钟。

之前从来不写文章,总感觉自己写的内容没什么价值。现在发现自己越不写越不知道该写些什么内容。从现在开始尝试写一些内容,锻炼自己。


昨天写了关于深浅拷贝的内容,今天来总结一下KVC和KVO。

######KVC(key - value - coding)键值编码

  • 它提供了一种使用字符串而不是通过访问方法访问对象属性的一种机制。
  • 通过setValue: forKey: 的方式对类属性进行赋值操作,key作为属性名,value为属性对应的值。
  • 通过valueForKey:访问对象的属性

可以通过以下简单的代码来尝试一下。 定义两个类,一个为Person

#import 
#import "Dog.h"@interface Person : NSObject { NSString *_sex; Dog *_dog;}@property (nonatomic, copy) NSString *name;//用来测试KVO对数组的效果@property (nonatomic, strong) NSMutableArray *dogs;- (void)showSex;- (void)showAge;- (void)showHeight;@end复制代码
#import "Person.h"@interface Person () {    NSString *age;}@property (nonatomic, copy) NSString *height;@end@implementation Person- (instancetype)init {        if (self = [super init]) {        _dog = [[Dog alloc]init];        _dogs = [NSMutableArray new];    }        return self;}- (void)showAge {    NSLog(@"age : %@",age);}- (void)showSex {    NSLog(@"sex : %@",_sex);}- (void)showHeight {    NSLog(@"height : %@",_height);}复制代码

一个为Dog类

#import 
@interface Dog : NSObject@property (nonatomic, copy) NSString *name;@end复制代码
#import "Dog.h"@interface Dog () {    NSString *_age;        NSMutableDictionary *_undefinedKeyDict;}@property (nonatomic, copy) NSString *weight;@end@implementation Dog- (void)setWeight:(NSString *)weight {    if (![_weight isEqualToString:weight]) {        _weight = [weight copy];    }}//不做实现的话会崩溃- (void)setValue:(id)value forUndefinedKey:(NSString *)key {        if (!_undefinedKeyDict) {        _undefinedKeyDict = [NSMutableDictionary dictionary];    }    [_undefinedKeyDict setObject:value forKey:key];    }- (id)valueForUndefinedKey:(NSString *)key {    return [_undefinedKeyDict objectForKey:key];}@end复制代码
Person *p = [[Person alloc]init];    p.name = @"vayne";    NSLog(@"name : %@",p.name);        [p setValue:@"famale" forKey:@"sex"];    [p showSex];        [p setValue:@"18" forKey:@"age"];    [p showAge];        [p setValue:@"185" forKey:@"height"];    [p showHeight];        Dog *d = [[Dog alloc]init];        d.name = @"huahua";    NSLog(@"dog name : %@",d.name);        [d setValue:@"duoduo" forKey:@"name"];    NSLog(@"dog name : %@",d.name);        [d setValue:@"30" forKey:@"weight"];    NSLog(@"weight : %@",[d valueForKey:@"weight"]);        [d setValue:@"3" forKey:@"age"];    NSLog(@"age : %@",[d valueForKey:@"age"]);        [p setValue:@"dog" forKeyPath:@"dog.name"];    NSLog(@"dog name : %@",[p valueForKeyPath:@"dog.name"]);    //keyPath dog.xxxx并不存在,如果在dog类中不实现setValue: forUndefinedKey 会崩溃。    [p setValue:@"xxxx" forKeyPath:@"dog.xxxx"];    NSLog(@"xxxx : %@",[p valueForKeyPath:@"dog.xxxx"]);    [d setValue:@"yyyy" forKey:@"yyyy"];    NSLog(@"yyyy : %@",[d valueForKey:@"yyyy"]);    复制代码

通过上边的简单代码可以对KVC有个简单的了解,正因为这个特性,我们可以通过KVC来调用一些私有属性。正因为这样,KVO就是基于KVC实现的

######KVO(key - value - observed)键值观察 观察者模式(有时又被成为订阅模式/发布模式)是软件设计模式的一种。在此模式中,一个目标对象管理所有相依赖于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫观察者所提供的方法来实现。

通过- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;添加观察机制。其中observer 观察方法的持有者,keyPath 属性的名字,options观察键值变化的几种可选方式,context可以传NULL

接上边的代码,看一下KVO

[p addObserver:self forKeyPath:@"sex" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];     [p setValue:@"male" forKey:@"sex"];    /*     如果被观察对象销毁,要移除其观察事件,否则会有崩溃。     */    [p removeObserver:self forKeyPath:@"sex"];    复制代码
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary
*)change context:(void *)context { NSLog(@"%@ %@ %@ %@ ",keyPath,[object class],change,context);}复制代码

当KVO作用于NSMutableArray时,观察并不会被调用,需要手动调用方法

//添加观察事件    [p addObserver:self forKeyPath:@"dogs" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];    //需要手动调用    [p willChangeValueForKey:@"dogs"];        [p.dogs addObject:d];    //需要手动调用    [p didChangeValueForKey:@"dogs"];        [p removeObserver:self forKeyPath:@"dogs"];复制代码

最后在做一个简单的UI变化。 在屏幕上放置一个按钮,两个不同颜色的view

@property (weak, nonatomic) IBOutlet UIView *blueView;@property (weak, nonatomic) IBOutlet UIView *redView;复制代码
//观察redView的frame变化    [self.redView addObserver:self forKeyPath:@"frame" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"frameChanged"];//将blueView的frame赋值给redView- (IBAction)changeFrame:(id)sender {        [UIView animateWithDuration:1 animations:^{               self.redView.frame = self.blueView.frame;            }];    }- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary
*)change context:(void *)context { NSLog(@"%@ %@ %@ %@ ",keyPath,[object class],change,context); //观察到redView的frame发生变化,之后将redView旧的值赋值给blueView,效果是两个view交换位置 [UIView animateWithDuration:1 animations:^{ self.blueView.frame = [[change objectForKey:@"old"]CGRectValue]; }]; }复制代码

KVO总结:

  • 在对象销毁前,要取消观察事件,否则会crash
  • 对被观察对象的数组属性,数组元素的改变无法调用观察事件,需要开发者手动操作。

转载于:https://juejin.im/post/5a333596f265da4310486bf7

你可能感兴趣的文章
spring mvc 返回json 数据
查看>>
我的友情链接
查看>>
SUSE下nx nomachine安装配置
查看>>
精通脚本***学习笔记(二)
查看>>
我的友情链接
查看>>
shell数组常见操作
查看>>
typedef用法
查看>>
oracle基本操作语句(初学者语句)
查看>>
【Android必备】应用小部件概述(23)
查看>>
【Interface&navigation】材料设计(20)
查看>>
我要学python之生成器
查看>>
ubuntu 13.04 安装QQ
查看>>
IOS图片的拉伸技巧
查看>>
tomcat安装
查看>>
KVM虚拟化的部署及使用
查看>>
Linux软链接和硬链接文件
查看>>
semaphore.h
查看>>
java学习笔记 --- 网络编程(套接字)
查看>>
tkinter 03 Listbox 列表部件
查看>>
Linux磁盘管理命令介绍
查看>>