iOS基础之KVC与KVO

1. 概述

ObjC主要基于Smalltalk进行设计, 因此它有很多类似Ruby,Python的动态特性, 例如动态类型,动态加载,动态绑定等. 因此可以ObjC中可以使用键值编码KVC 和 键值监听KVO; 基于观察者思想:

一个目标对象 管理所有依赖于它的 观察者对象;并在自身的状态改变时 主动通知观察者对象. 通知通告调用各观察着对象所提供的接口方法实现, 观察者模式 为了解耦;

1. KVC

C#中可以通过反射读写一个对象的属性, 利用字符串的方式去动态控制一个对象. 但是对于ObjC的runtime特性, 我们不需要进行任何操作即可进行属性的动态读写,

KVC的操作方法有NSKeyValueCoding协议提供, NSObject遵守了这个协议, 所以OC的对象都可以使用KVC;

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

注意:

  1. KVC 可以访问私有变量.
  2. valueForKey会自动把基本类型转成NSNumber或NSValue中包装成对象,同样,动态设置setValue: forKey:的属性也必须先包装成NSNumber对象类型才可以.

查找规律:

  1. 先检查是否存在属性a的set和get方法(BOOL类型属性的get方法名是is<key>), 没有就会搜索_<key>/_set<key>方法.
  2. 如果还没有再搜索成员变量_a, 如果仍不存在,就会搜索成员变量a
  3. 如果最后仍没搜索到, 会根据设值还是取值 调用 setValue:forUndefinedKey:或valueforUndefineKey: 抛出异常.根据需要重写它们;

补充

批处理:

KVC可以对对象进行批量更改,dictionaryWithValuesForKeys:和setValuesForKeysWithDictionary:dict;

数组的整体操作:

如果向一个数组请求一个key,KVC会查询数组中每个对象来查找这个key,之后会将结果打包到一个新数组并返回;例:student有很多book, 获取book的nameNSArray *names = [student valueForKeyPath:@"books.name"];

键路径的运算符:

在路径中,可以引用一下运算符@xxxxx来进行一些运算,例如获取一组值得平均值,最值或者总数.

  1. 简单运算符@avg @count @max @min @sum
  2. 对象运算符: @distinctUnionOfObjects(去掉重复) @unionOfObjects(不去重复),都返回数组
  3. Array和Set操作符: 集合中包含集合的情况.
NSNumber *count = [student valueForKeyPath:@"books.@count"];//计算总数
NSNumber *sum = [student valueForKeyPath:@"books.@sum.price"];//总和
NSArray *prices = [student valueForKeyPath:@"books.@distinctUnionOfObjects.price"]; 

KVO

//1. 注册监听器
-(void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
anObserver :监听器对象
keyPath :监听的属性
options :决定了当属性改变时,要传递什么数据给监听器

//2.监听器需要实现监听方法,来处理收到的通知;
-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context
keyPath :监听的属性
object :谁的属性改变了
change :属性改变时传递过来的信息(取决于添加监听器时的options参数

//3. 最后移除监听器
-(void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath

注册和解除注册定义在NSKeyValueObserving协议中, NSObject,NSArray,NSSet实现了此协议;

KVO实现机制:

当某个类的对象第一次被观察时,系统就会在 运行时动态的创建该类的一个派生类, 在这个派生类中重写原类中被观察属性的setter方法;
派生类在被重写的setter方法中实现真正的 通知机制. 这是基于设置属性会调用setter方法,而通过重写就可以获得KVO需要的通知机制. (所以,使用KVO要遵循其属性设置方式来改变属性值, 如果仅仅直接修改属性值,是无法实现KVO的); (补充: Swift中的属性观察器原理相似)

- (void) setAge:(int)theAge
{
    // will和did两个方法用于通知系统该key的属性值即将和已经变更
    [self willChangeValueForKey:@"age"];
    age = theAge;
    [self didChangeValueForKey:@"age"]; 
}
//didChangeValueForKey方法会调用下面方法,
+(BOOL) automaticallyNotifiesObserversForKey:(NSString *)key {
    if ([key isEqualToString:@"age"]) {
        return NO;
    }
    return [super automaticallyNotifiesObserversForKey:key];
}

同时派生类还重写了class方法以"欺骗"外部调用者它就是起初的那个类.然后系统将这个对象的isa指针指向了这个新诞生的派生类, 之后调用该对象的setter就会调用重写后的setter从而激活通知
机制.当然,派生类还重写了dealloc方法来释放资源.

总结: KVO的三种方式:
  1. 使用了KVC情况下:如果有访问器方法,则运行时会在访问器方法中调用will/didChangeValueForKey:方法; 如果没有访问器方法,运行时会在setValue:forKey方法中调用will/didChangeValueForKey:方法;
  2. 有访问器方法: 运行时会重写访问器方法来调用will/didChangeValueForKey:;
  3. 如果没有使用KVC,且没有访问器方法, 可以显示调用will/didChangeValueForKey:.就同样可以使用KVO;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342

推荐阅读更多精彩内容