Object C KVC & KVO & NOtification

一. KVC

間接的修改或獲取對(duì)象的屬性,降低程序(類與類)之間的耦合度.

常見(jiàn)的兩種用法

1.對(duì)私有變量進(jìn)行賦值,同樣的也可以通過(guò)它進(jìn)行取值
在使用KVC時(shí), 一定要保證鍵值是存在的.

#KVC最為重要的四個(gè)方法
- (nullable id)valueForKey:(NSString *)key;                          //直接通過(guò)Key來(lái)取值

- (void)setValue:(nullable id)value forKey:(NSString *)key;          //通過(guò)Key來(lái)設(shè)值

- (nullable id)valueForKeyPath:(NSString *)keyPath;                  //通過(guò)KeyPath來(lái)取值

- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  //通過(guò)KeyPath來(lái)設(shè)值屬性


#NSKeyValueCoding類別中其他的一些方法:
//默認(rèn)返回YES赦拘,表示如果沒(méi)有找到Set<Key>方法的話像捶,會(huì)按照_key吴裤,_iskey铺罢,key,iskey的順序搜索成員,設(shè)置成NO就不這樣搜索
+ (BOOL)accessInstanceVariablesDirectly;

//KVC提供屬性值正確性驗(yàn)證的API听绳,它可以用來(lái)檢查set的值是否正確垃环、為不正確的值做一個(gè)替換值或者拒絕設(shè)置新值并返回錯(cuò)誤原因邀层。
- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;

//這是集合操作的API,里面還有一系列這樣的API遂庄,如果屬性是一個(gè)NSMutableArray寥院,那么可以用這個(gè)方法來(lái)返回。
- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;

//如果Key不存在涛目,且沒(méi)有KVC無(wú)法搜索到任何和Key有關(guān)的字段或者屬性只磷,則會(huì)調(diào)用這個(gè)方法,默認(rèn)是拋出異常泌绣。
- (nullable id)valueForUndefinedKey:(NSString *)key;

//和上一個(gè)方法一樣,但這個(gè)方法是設(shè)值预厌。
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;

//如果你在SetValue方法時(shí)面給Value傳nil阿迈,則會(huì)調(diào)用這個(gè)方法
- (void)setNilValueForKey:(NSString *)key;

//輸入一組key,返回該組key對(duì)應(yīng)的Value,再轉(zhuǎn)成字典返回轧叽,用于將Model轉(zhuǎn)到字典苗沧。
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;

例子

#import <Foundation/Foundation.h>

@interface Test: NSObject {
    NSString *_name;
}

@end

@implementation Test

@end

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        //生成對(duì)象
        Test *obj = [[Test alloc] init];
        //通過(guò)KVC賦值name
        [obj setValue:@"xiaoming" forKey:@"name"];
        //通過(guò)KVC取值name打印
        NSLog(@"obj的名字是%@", [obj valueForKey:@"name"]);
        
    }
    return 0;
}

2.字典轉(zhuǎn)模型

obj.name=dic[@"name"];
obj.sex=dic[@"sex"];
obj.age=dic[@"age"];

//將以上代碼替換為一行代碼
[obj setValuesForKeysWithDictionary:dic];

二. KVO

對(duì)目標(biāo)對(duì)象的某屬性添加觀察,當(dāng)該屬性發(fā)生變化時(shí)炭晒,通過(guò)觸發(fā)觀察者對(duì)象實(shí)現(xiàn)的KVO接口方法待逞,來(lái)自動(dòng)的通知觀察者

*KVO使用步驟:

/***
keyPath:描述將要觀察的屬性,相對(duì)于被觀察者网严。

options:KVO的一些屬性配置识樱;有四個(gè)選項(xiàng)。
NSKeyValueObservingOptionNew:change字典包括改變后的值
NSKeyValueObservingOptionOld:change字典包括改變前的值
NSKeyValueObservingOptionInitial:注冊(cè)后立刻觸發(fā)KVO通知
NSKeyValueObservingOptionPrior:值改變前是否也要通知(這個(gè)key決定了是否在改變前改變后通知兩次)

context: 上下文震束,這個(gè)會(huì)傳遞到訂閱著的函數(shù)中怜庸,用來(lái)區(qū)分消息,所以應(yīng)當(dāng)是不同的垢村。
***/
[stuaddObserver:selfforKeyPath:@"name"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"myObserver"];
//當(dāng)指定鍵值發(fā)生改變時(shí), 會(huì)自動(dòng)調(diào)用這個(gè)方法
observeValueForKeyPath.  
 //所有觀察者模式的性能都不好,需要及時(shí)移除割疾。
removeObserver.

例子

//  
//  XNViewController.m  
//  KVC----KVO  
//  
//  Created by neng on 14-6-21.  
//  Copyright (c) 2014年 neng. All rights reserved.  
//  
  
#import "XNViewController.h"  
#import "XNPerson.h"  
#import "XNStudent.h"  
#import "XNBook.h"  
  
@interface XNViewController ()  
  
@end  
/** 
 *  KVC: Key Value Coding(鍵值編碼) 
 *  間接修改/獲取對(duì)象的屬性, 降低類與類之間的耦合度. 
 *  KVO: Key Value Observer(鍵值觀察) 
   KVO通常用于觀察”對(duì)象的某個(gè)屬性“發(fā)生變化時(shí),及時(shí)做出響應(yīng)嘉栓! 
   而NSNotificationCenter是需要POST"通知字符串"(表示監(jiān)聽(tīng)的事件類型)的對(duì)象存在宏榕,通知中心才能夠工作! 
 */  
  
@implementation XNViewController  
  
- (void)viewDidLoad {  
    [super viewDidLoad];  
    //1.簡(jiǎn)單的修改對(duì)象屬性  
    [self kvcDemo1];  
    //2.對(duì)于子類, 也能直接修改  
    [self kvcDemo2];  
  
    //KVO 演示  
    [self kvoDemo];  
}  
  
- (void)kvoDemo {  
    XNStudent *stu = [[XNStudent alloc] init];  
    stu.name = @"xuneng";  
    //設(shè)置監(jiān)聽(tīng)對(duì)象  
    //1》 負(fù)責(zé)觀察的對(duì)象 self  
    //2》 觀察的鍵值路徑  
    //3》 觀察的選項(xiàng)  
    //4》 上下文:通常用于區(qū)分不同的觀察事件  
    [stu addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"myObserver"];  
  
    stu.name = @"neng"; //修改  
  
    //所有觀察者模式的性能都不好, 需要及時(shí)移除  
    [stu removeObserver:self forKeyPath:@"name"];  
  
    stu.name = @"xu";  //移除后再次修改  
}  
  
/** 
   當(dāng)KVO指定的對(duì)象鍵值發(fā)生改變時(shí), 會(huì)自動(dòng)調(diào)用該方法 
   name:      觀察的鍵值 
   object:    觀察的對(duì)象 
   change:    修改的字典(新舊數(shù)值) 
   context:   指定觀察者時(shí)傳入的上下文 
 */  
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(voidvoid *)context {  
    NSLog(@"|-- %@ --|-- %@ --|-- %@ --|-- %@--|", keyPath, object, change, context);  
}  
  
/** 
 *簡(jiǎn)單的修改對(duì)象屬性 
 */  
- (void)kvcDemo1 {  
    //1.原始的方式. 點(diǎn)語(yǔ)法修改對(duì)象屬性的值  
    XNPerson *p1 = [[XNPerson alloc] init];  
    p1.name = @"xuneng";  
    p1.age = 24;  
    //    NSLog(@"%@ , %d",p1.name,p1.age);  
    NSLog(@"KVC1 demo1--> %@", p1); //這樣直接調(diào)用description方法.  
  
    //2.KVC來(lái)修改  
    [p1 setValue:@"xxxx" forKeyPath:@"name"];  
    [p1 setValue:@"10" forKeyPath:@"age"];  
    NSLog(@"KVC2 demo1--> %@ , %d", p1.name, p1.age);  
}  
  
/** 
 *對(duì)于子類, 也能直接改 
 */  
- (void)kvcDemo2 {  
    //1.傳統(tǒng)方法  
    XNStudent *p1 = [[XNStudent alloc] init]; //學(xué)生  
    p1.name = @"student xuneng";  
    p1.age = 22;  
    //    NSLog(@"%@ , %d",p1.name,p1.age);  
    NSLog(@"KVC1 demo2--> %@", p1); //這樣直接調(diào)用description方法.  
  
    //2.KVC來(lái)修改子類  
    [p1 setValue:@"xxxx" forKeyPath:@"name"];  
    [p1 setValue:@"10" forKeyPath:@"age"];  
    NSLog(@"KVC2 demo2--> %@ , %d", p1.name, p1.age);  
}  
@end  

1. 如何手動(dòng)觸發(fā)KVO侵佃?
答: 被監(jiān)聽(tīng)的屬性的值被修改時(shí)麻昼,就會(huì)自動(dòng)觸發(fā)KVO。如果想要手動(dòng)觸發(fā)KVO趣钱,則需要我們自己調(diào)用willChangeValueForKey和didChangeValueForKey方法即可在不改變屬性值的情況下手動(dòng)觸發(fā)KVO涌献,并且這兩個(gè)方法缺一不可。

2. 直接修改成員變量會(huì)觸發(fā)KVO嗎首有?
答:不會(huì)觸發(fā)

3. 通過(guò)KVC修改屬性會(huì)觸發(fā)KVO么燕垃?
答:會(huì)觸發(fā)


三枢劝、NSNotification

使用觀察者模式來(lái)實(shí)現(xiàn)的用于跨層傳遞消息。往往也用NSNotification來(lái)實(shí)現(xiàn)解耦的目的卜壕。
常見(jiàn)的還有代理傳值您旁、block傳值等。(代理實(shí)現(xiàn)和block一般用于一對(duì)一的情況轴捎。)

IOS NSNotification 通知 - 冬季的暖風(fēng) - 博客園 (cnblogs.com)

參考:
iOS KVC和KVO詳解 - 簡(jiǎn)書 (jianshu.com)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鹤盒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子侦副,更是在濱河造成了極大的恐慌侦锯,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,884評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件秦驯,死亡現(xiàn)場(chǎng)離奇詭異尺碰,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)译隘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,347評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門亲桥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人固耘,你說(shuō)我怎么就攤上這事题篷。” “怎么了厅目?”我有些...
    開封第一講書人閱讀 157,435評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵番枚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我璧瞬,道長(zhǎng)户辫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,509評(píng)論 1 284
  • 正文 為了忘掉前任嗤锉,我火速辦了婚禮渔欢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瘟忱。我一直安慰自己奥额,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,611評(píng)論 6 386
  • 文/花漫 我一把揭開白布访诱。 她就那樣靜靜地躺著垫挨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪触菜。 梳的紋絲不亂的頭發(fā)上九榔,一...
    開封第一講書人閱讀 49,837評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼哲泊。 笑死剩蟀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的切威。 我是一名探鬼主播育特,決...
    沈念sama閱讀 38,987評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼先朦!你這毒婦竟也來(lái)了缰冤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,730評(píng)論 0 267
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤喳魏,失蹤者是張志新(化名)和其女友劉穎棉浸,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體刺彩,經(jīng)...
    沈念sama閱讀 44,194評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡涮拗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,525評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了迂苛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,664評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡鼓择,死狀恐怖三幻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情呐能,我是刑警寧澤念搬,帶...
    沈念sama閱讀 34,334評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站摆出,受9級(jí)特大地震影響朗徊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜偎漫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,944評(píng)論 3 313
  • 文/蒙蒙 一爷恳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧象踊,春花似錦温亲、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,764評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至史隆,卻和暖如春魂务,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,997評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工粘姜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留鬓照,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,389評(píng)論 2 360
  • 正文 我出身青樓相艇,卻偏偏與公主長(zhǎng)得像颖杏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坛芽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,554評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容