kvo實現原理 KVO的本質是什麼?

2021-10-14 10:33:45 字數 3663 閱讀 9702

person 類

@inte***ce person : nsobject

@property (nonatomic, assign)nsinteger age;

@property (nonatomic, assign)nsinteger height;

@end

@implementation person

@end

監聽person類的age屬性的變更

#import "person.h"

@inte***ce viewcontroller ()

@property (strong, nonatomic) person *person;

@end

@implementation viewcontroller

- (void)viewdidload

//當監聽物件的屬性值發生改變時,就會呼叫

- (void)observevalueforkeypath:(nsstring *)keypath ofobject:(id)object change:(nsdictionary*)change context:(void *)context

- (void)touchesbegan:(nsset*)touches withevent:(uievent *)event

-(void)dealloc

@end

使用上的幾個注意點:

要監聽的物件addobserver: forkeypath: options: context:方法。其中第乙個引數表示在哪個類中響應監聽方法,一般是self,第二個引數表示要監聽的key,第三個引數表示要傳入監聽方法中的值的選項,本例中新值、舊值都會傳入,最後乙個引數表示額外需要傳入監聽方法的引數。

實現監聽方法observevalueforkeypath: ofobject: change: context:

在dealloc方法中移除監聽。

我們通過在touchesbegan: withevent:方法裡增加斷點,檢視兩個person例項物件的isa指標指向。

(lldb)po self.person->isanskvonotifying_person(lldb)po self.person2->isaperson(lldb)po class_getsuperclass(object_getclass(self.person))//獲取superclass的指向

person

通過lldb檢視,我們得出增加kvo監聽後person的isa指向了nskvonotifying_person而不是person。而nskvonotifying_person的superclass指向person。 如下圖:

那麼,當我們修改age的值的時候是如何觸發監聽的呢?

修改值觸發監聽的呼叫過程:

呼叫nskvonotifying_person的setage方法。

setaage方法內部呼叫_nssetlonglon**alueandnotify

_nssetlonglon**alueandnotify內部呼叫willchangevalueforkey:_nssetlonglon**alueandnotify內部呼叫super setage_nssetlonglon**alueandnotify內部呼叫didchangevalueforkey:didchangevalueforkey內部呼叫observevalueforkeypath: ofobject: change: context我們通過實現兩個方法printmethodsprintvars來實現列印物件內部的方法和成員變數。

- (void)printmethods:(class)cls 

- (void)willchangevalueforkey:(nsstring *)key

- (void)didchangevalueforkey:(nsstring *)key

列印日誌:

2020-05-26 07:31:57.980860+0800 kvo[45585:524051] willchangevalueforkey2020-05-26 07:31:57.981072+0800 kvo[45585:524051] setage:2020-05-26 07:31:57.981184+0800 kvo[45585:524051] didchangevalueforkey---start2020-05-26 07:31:57.981454+0800 kvo[45585:524051] 監聽到了-的-age發了改變-2020-05-26 07:31:57.981618+0800 kvo[45585:524051] didchangevalueforkey---end
[self.person willchangevalueforkey:@"age"]; //這個方法需要呼叫,否則觸發不成功

[self.person didchangevalueforkey:@"age"];

nsset***valueandnotify 有如下這麼多型別,可以通過反編輯foundation框架來獲得,具體不再贅述,這不是重點。

_nssetboolvalueandnotify、_nssetcharvalueandnotify、_nssetdoublevalueandnotify、_nssetfloatvalueandnotify、_nssetintvalueandnotify、_nssetlonglon**alueandnotify、_nssetlon**alueandnotify、_nssetobjectvalueandnotify、_nssetpointvalueandnotify、_nssetrangevalueandnotify、_nssetrectvalueandnotify、_nssetshortvalueandnotify、_nssetsizevalueandnotify、_nssetunsignedcharvalueandnotify、_nssetunsignedintvalueandnotify、_nssetunsignedlonglon**alueandnotify、_nssetunsignedlon**alueandnotify、_nssetunsignedshortvalueandnotify、

KVO實現原理

kvo的執行原理是基於執行時的 當乙個物件註冊了監聽者以後 程式執行時就會動態的建立被監聽者的乙個子類 nskvonotifying 建立該子類的物件 kvo只能監聽物件屬性通過setter方法改變時監聽 1 當乙個object有觀察者時,動態建立這個object的類的子類 2 對於每個被觀察的pr...

KVO 實現原理

1.self.person 要監聽的物件 2.引數說明 param addobserver 觀察者,負責處理監聽事件的物件 param forkeypath 要監聽的屬性 param options 觀察的選項 觀察新 舊值,也可以都觀察 param context 上下文,用於傳遞資料,可以利用上...

KVO實現原理

kvo 的全稱是 key value observing 俗稱 鍵值監聽 可以用於監聽某個物件屬性值的改變。下面來 一下kvo的本質 1.新建乙個xzperson類 import inte ce xzperson nsobject property nonatomic,assign int age ...