iOS開(kāi)發(fā)之--KVO詳解

如果你從事iOS開(kāi)發(fā),
對(duì)于KVO肯定不陌生.
今天寫了這篇文章,
讓我們進(jìn)一步了解KVO,
我們從下圖幾個(gè)部分了解KVO,
如果你看了這篇文章,
會(huì)顛覆你對(duì)KVO的認(rèn)知,
原來(lái)你了解過(guò)得KVO只是一部分.

1.什么是KVO?

KVO(Key Value Observing, 鍵值觀察)是Objective-C對(duì)觀察者模式的實(shí)現(xiàn),每次當(dāng)被觀察對(duì)象的某個(gè)屬性值發(fā)生改變時(shí),注冊(cè)的觀察者便能獲得通知。

作為一個(gè)開(kāi)發(fā)者,有一個(gè)學(xué)習(xí)的氛圍跟一個(gè)交流圈子特別重要,這是一個(gè)我的iOS交流群:638302184,不管你是小白還是大牛歡迎入駐 ,分享BAT,阿里面試題、面試經(jīng)驗(yàn),討論技術(shù), 與2800+iOS開(kāi)發(fā)者一起交流學(xué)習(xí)成長(zhǎng)!

2.KVO的使用

這里我們結(jié)合代碼了解KVO,
單純的文字描述已經(jīng)沒(méi)有發(fā)言權(quán).

  • 案例一:
    1.1我們先創(chuàng)建一個(gè)person類
#import <Foundation/Foundation.h>
@interface Person : NSObject{
@property(nonatomic,copy)NSString *name;
@end
#import "Person.h"
@implementation Person
@end

并為person添加屬性name

此時(shí),我們已經(jīng)創(chuàng)建好了person類

1.2接著,我們?cè)趘iewDidLoad方法中創(chuàng)建Person對(duì)象

//方便引用
@property(nonatomic,strong)Person *p;
 Person *p = [[Person alloc]init];
    //引用
 _p = p;

p指針在哪個(gè)地方? p指針指向引用數(shù)據(jù)類型,對(duì)象在堆區(qū),指針在棧區(qū).

1.3接著我們?cè)赩iewDidLoad方法中添加觀察

[圖片上傳失敗...(image-532afe-1577458318977)]

 [p addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:nil];

1.4使用touchesBegan時(shí)間,改變屬性值,以方便進(jìn)行觀察.

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    static int a;
    _p.name = [NSString stringWithFormat:@"%d",a++];
}

1.5此時(shí)我們運(yùn)行會(huì)不會(huì)有結(jié)果呢?

答案是我們點(diǎn)擊屏幕的時(shí)候,程序會(huì)崩潰.因?yàn)槲覀冞@里沒(méi)有去響應(yīng).
我們要添加響應(yīng)的方法

//響應(yīng)方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    //觀察者觀察name的變化,當(dāng)點(diǎn)擊屏幕,改變name的值,chang就會(huì)捕獲新值.
    NSLog(@"%@",change);
}

1.6,此時(shí)你運(yùn)行起來(lái)點(diǎn)屏幕幾下.控制臺(tái)就會(huì)有輸出了.

2018-03-31 18:38:54.319824+0800 001--kvo使用[2725:50940] {
    kind = 1;
    new = 0;
}

案例一,創(chuàng)建了基本簡(jiǎn)答的KVO.

  • 案例二

如果我們改變了name的屬性,observe回調(diào)就來(lái)了,這就是自動(dòng)觸發(fā).
還有只用,變化了不一定每一次都通知,平常開(kāi)發(fā)需求也會(huì)遇到.
如果滿足了某一個(gè)條件的時(shí)候,我們來(lái)通知一下.

2.1我們?cè)趐erson中添加一個(gè)方法

+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
    //手動(dòng)觸發(fā)
    return NO;
    //自動(dòng)觸發(fā)
   // return YES;
}

2.2這個(gè)時(shí)候,我們回到ViewController中,對(duì),touchBegan方法進(jìn)行修改,就可以完成手動(dòng)觸發(fā).

    static int a;
    //手動(dòng)觸發(fā)
    //即將改變
    [_p willChangeValueForKey:@"name"]
    _p.name = [NSString stringWithFormat:@"%d",a++];
    // 改變完成
    [_p didChangeValueForKey:@"name"];
    ```
    
2.3如果我們想滿足一個(gè)條件后,進(jìn)行屬性觀察.
我們就要在 automaticallyNotifiesObserversForKey:(NSString *)key
通過(guò)判斷key來(lái)進(jìn)行手動(dòng)觸發(fā)或者自動(dòng)觸發(fā).
比如,我們判斷是name的時(shí)候,我們手動(dòng)觸發(fā)
//手動(dòng)觸發(fā)
if([key isEqualToString:@"name"]){
    return NO;
}
return YES;
```

案例二,手動(dòng)觸發(fā),自動(dòng)觸發(fā)

  • 案例三
    我們創(chuàng)建一個(gè)dog類,.我們想觀察person中的dog屬性的變化,我們可以這樣注冊(cè).

3.1首先,我們先創(chuàng)建dog類

#import <Foundation/Foundation.h>
@interface Dog : NSObject
@property(nonatomic,assign)int age;
@end
#import "Dog.h"
@implementation Dog
@end

3.2我們?cè)趐erson中加入

@property(nonatomic,strong)Dog *dog;

3.3對(duì)dog進(jìn)行初始化

-(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在點(diǎn)擊事件中,改變age的值

 _p.dog.age = a++;

我們觀察到dog的age值變化

  • 案例四:
    4.1我們?cè)赿og類中加入level
@property(nonatomic,assign)int level;

4.2通過(guò)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在點(diǎn)擊事件中,改變age和level

//    _p.dog.age = a++;
//    _p.dog.level = a++;
4.4運(yùn)行后,我們就可以看到屬性值的變化.

案例四,是不是有些麻煩呢,這種方式我們要寫兩次

4.KVO觀察容器

  • 1.KVO --響應(yīng)式編程
    首先,我們需要添加,訂閱,然后有響應(yīng)的方法
    代理是么?其實(shí)代理也一樣
    比如tableView,我們添加代理,就可以使用代理方法,代理方法回調(diào).
    比如button時(shí)間,其實(shí)也是響應(yīng)式編程,為button添加target,開(kāi)啟方法,方法調(diào)用.

  • 2.我們?cè)诎咐刑岬搅藬?shù)組,我們初始化后并沒(méi)有觀察到person中array屬性的變化

我們這次就要借助KVC

2.1我們創(chuàng)建person類,加入arr屬性

@property(nonatomic,strong)NSMutableArray *arr;

2.2初始化數(shù)組

- (instancetype)init
{
    self = [super init];
    if (self) {
        _arr = NSMutableArray.array;
    }
    return self;
}

2.3在VC中

@property(nonatomic,strong)Person *p;

2.4創(chuàng)建person對(duì)象,添加觀察者

 Person *p = [[Person alloc]init];
    
    _p = p;

[_p addObserver:self forKeyPath:@"name" options:(NSKeyValueObservingOptionNew) context:nil];

2.5響應(yīng)方法

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
    NSLog(@"%@",change);    
}

2.6touchesBegan中加入

//KVO監(jiān)聽(tīng)容器方法,需要借助KVC

NSMutableArray *tempArr =    [_p mutableArrayValueForKeyPath:@"arr"];
[tempArr addObject:@"123"];

2.7程序跑起來(lái),我們?cè)诳刂婆_(tái)可以看到

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,

有沒(méi)有顛覆KVO調(diào)setter方法,還可以調(diào)用insert,remove,replace
這里輸出的kind2,說(shuō)明了插入的數(shù)據(jù)的時(shí)候,觀察者也可以觀察到屬性值的變化.
如果沒(méi)有深入了解一下KVO,知道了KVO不僅可以調(diào)用setter方法,還可以調(diào)用插入,刪除,代替方法.

### 總結(jié)
1.動(dòng)態(tài)創(chuàng)建Person的子類使用
2.子類重寫setName
3.動(dòng)態(tài)修改了對(duì)象的類型
4.還了解到了,KVO不僅可以調(diào)用setter方法,還可以調(diào)用插入,刪除,代替方法.通過(guò)對(duì)kvo的進(jìn)一步了解,我們是很清楚KVO底層運(yùn)用.
好的,這就是KVO.
這篇文章能幫到您,
請(qǐng)您點(diǎn)個(gè)贊
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,488評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,034評(píng)論 3 414
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 175,327評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,554評(píng)論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,337評(píng)論 6 404
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 54,883評(píng)論 1 321
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評(píng)論 3 439
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,114評(píng)論 0 286
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,625評(píng)論 1 332
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,555評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,737評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評(píng)論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 43,973評(píng)論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,362評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,615評(píng)論 1 280
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,343評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,699評(píng)論 2 370

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

  • 什么是KVO? KVO 全稱 Key Value Observing,是蘋果提供的一套事件通知機(jī)制。允許對(duì)象監(jiān)聽(tīng)另...
    薩繆閱讀 7,661評(píng)論 0 17
  • 什么是KVO? KVO 全稱 Key Value Observing,是蘋果提供的一套事件通知機(jī)制。允許對(duì)象監(jiān)聽(tīng)另...
    薩繆閱讀 562評(píng)論 0 1
  • 什么是KVO? KVO 全稱 Key Value Observing,是蘋果提供的一套事件通知機(jī)制。允許對(duì)象監(jiān)聽(tīng)另...
    祀夢(mèng)_閱讀 491評(píng)論 0 4
  • 本文僅是記錄自己在學(xué)習(xí)的過(guò)程中的理解:如有錯(cuò)誤,還望各位大佬指正,THX. KVO全稱KeyValueObserv...
    Henry_Jeannie閱讀 1,912評(píng)論 0 4
  • ||草鋪導(dǎo)讀: 我們常常因?yàn)椴蛔灾贫鴮?dǎo)致的拖延,被拉進(jìn)“焦慮怪圈”。一生都不去做有挑戰(zhàn)的事,最后自己也成了平庸的大...
    草鋪半生閱讀 522評(píng)論 0 9