在Swift中使用KVO的細(xì)節(jié)以及內(nèi)部實(shí)現(xiàn)解析(推薦)
KVO是什么?
KVO 是 Objective-C 對(duì)觀察者設(shè)計(jì)模式的一種實(shí)現(xiàn)?!玖硗庖环N是:通知機(jī)制(notification),詳情參考:iOS 趣談設(shè)計(jì)模式——通知】;
KVO提供一種機(jī)制,指定一個(gè)被觀察對(duì)象(例如A類),當(dāng)對(duì)象某個(gè)屬性(例如A中的字符串name)發(fā)生更改時(shí),對(duì)象會(huì)獲得通知,并作出相應(yīng)處理;【且不需要給被觀察的對(duì)象添加任何額外代碼,就能使用KVO機(jī)制】
在MVC設(shè)計(jì)架構(gòu)下的項(xiàng)目,KVO機(jī)制很適合實(shí)現(xiàn)mode模型和view視圖之間的通訊。
例如:代碼中,在模型類A創(chuàng)建屬性數(shù)據(jù),在控制器中創(chuàng)建觀察者,一旦屬性數(shù)據(jù)發(fā)生改變就收到觀察者收到通知,通過(guò)KVO再在控制器使用回調(diào)方法處理實(shí)現(xiàn)視圖B的更新;(本文中的應(yīng)用就是這樣的例子.)
實(shí)現(xiàn)原理?
KVO在Apple中的API文檔如下:
Automatic key-value observing is implemented using a technique called isa-swizzling… When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class …
KVO 的實(shí)現(xiàn)依賴于 Objective-C 強(qiáng)大的 Runtime【可參考:Runtime的幾個(gè)小例子】 ,從以上Apple 的文檔可以看出蘋果對(duì)于KVO機(jī)制的實(shí)現(xiàn)是一筆帶過(guò),而具體的細(xì)節(jié)沒(méi)有過(guò)多的描述,但是我們可以通過(guò)Runtime的所提供的方法去探索,關(guān)于KVO機(jī)制的底層實(shí)現(xiàn)原理。為此啊左從網(wǎng)上的一些關(guān)于KVO的資料總結(jié)了有關(guān)的內(nèi)容:
基本的原理:
當(dāng)觀察某對(duì)象A時(shí),KVO機(jī)制動(dòng)態(tài)創(chuàng)建一個(gè)對(duì)象A當(dāng)前類的子類,并為這個(gè)新的子類重寫了被觀察屬性keyPath的setter 方法。setter 方法隨后負(fù)責(zé)通知觀察對(duì)象屬性的改變狀況。
好了,下面本文重點(diǎn)內(nèi)容:
在文字的開頭,先說(shuō)一個(gè)小細(xì)節(jié),swift中聲明一個(gè)類,你可以集成自NSObject,也可以選擇忽略,二者有什么區(qū)別呢。根據(jù)自己的經(jīng)驗(yàn),我得出以下結(jié)論。不足之處,請(qǐng)指出。exmple:我們聲明這樣一個(gè)類
class Person: NSObject {
var name: String?
override init() {
super.init()
}
}
此類打印出的內(nèi)存地址是0x00000fbd00007ffeefbfc240
這段代碼是不會(huì)報(bào)錯(cuò)的,是一個(gè)典型的swift遺留ObjC語(yǔ)法的寫法,但是如果我們?nèi)サ鬘SObject并打印出他的內(nèi)存地址,如下
class Person {
var name: String?
init() {
}
}
此類打印出的內(nèi)存地址是0x00007ffeefbfc240
- 內(nèi)存地址不一樣,繼承自NSObject的類對(duì)象的內(nèi)存地址明顯長(zhǎng)度多了8個(gè)長(zhǎng)度,why?多出的8個(gè)空間就是為了存放ObjC對(duì)象內(nèi)的isa指針,有興趣的可以往下研究。
- 繼承自NSObject的類可以使用OC里的一些騷操作,比如KVC、KVO、runtime,否則使用setValue-forKey時(shí)是會(huì)報(bào)錯(cuò)的。
區(qū)別還有很多,平時(shí)在開發(fā)中大家可以多注意這一區(qū)別。個(gè)人偏向不繼承NSObject,尤其是我需要此類做一些騷操作時(shí),比如KVO。
KVO是OC一個(gè)對(duì)象屬性的特性,由于是面向字符串,所以開發(fā)時(shí)需要尤其小心,這種奔潰只有執(zhí)行到了才會(huì)報(bào)錯(cuò)。聲明如下類:
class Person: NSObject {
@objc var age: Int?
var name: String?
var observation: NSKeyValueObservation?
override init() {
super.init()
self.observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in
print("Person.age的新值 = ", change.newValue as Any)
})
}
}
在外部我們,初始化一個(gè)對(duì)象,并對(duì)age進(jìn)行賦值,如下
let person = Person() person.age = 18 person.setValue(100, forKey: "age")
程序執(zhí)行后,(ÒωÓױ)!為什么只有一個(gè)打?。堪蠢碚f(shuō)是應(yīng)該打印Person.age的新值 = 18和Person.age的新值 = 100的呀,然而并沒(méi)有:laughing:。問(wèn)題出在哪,原來(lái),swift中如果需要對(duì)一個(gè)值進(jìn)行監(jiān)聽,那么一定要記住2個(gè)關(guān)鍵詞
- @objc
- dynamic
否則,
沒(méi)有@objc程序在監(jiān)聽時(shí)會(huì)觸發(fā)奔潰;沒(méi)有dynamic則屬性的set方法不會(huì)生效,自然就沒(méi)有上面的打印,因?yàn)镵VO的本質(zhì)就是監(jiān)聽屬性的set方法,而可變數(shù)組的增刪操作都不會(huì)生效;
但是為什么KVC的操作卻能生效呢?這是因?yàn)镵VC內(nèi)部的實(shí)現(xiàn)過(guò)程是
- [person willChangeValueForKey:@"age"];
- person->_age = 10;
- [person didChangeValueForKey:@"age"];
- 而didChangeValueForKey:內(nèi)部會(huì)調(diào)用observe的observeValueForKeyPath:ofObject:change:context:的方法,也就觸發(fā)了KVO
所以正確的寫法應(yīng)該是
class Person: NSObject {
@objc dynamic var age: Int?
var name: String?
var observation: NSKeyValueObservation?
override init() {
super.init()
self.observation = observe(\Person.age, options: .new, changeHandler: { (person, change) in
print("Person.age的新值 = ", change.newValue as Any)
})
}
}
到此這篇關(guān)于在Swift中使用KVO的細(xì)節(jié)以及內(nèi)部實(shí)現(xiàn)解析的文章就介紹到這了,更多相關(guān)Swift使用KVO內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
iOS UITableView展開縮放動(dòng)畫實(shí)例代碼
這篇文章主要介紹了Swift UITableView展開縮放動(dòng)畫實(shí)例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
Swift 3.1聊天界面鍵盤效果的實(shí)現(xiàn)詳解
這篇文章主要給大家介紹了Swift 3.1聊天界面鍵盤效果實(shí)現(xiàn)的相關(guān)資料,文中介紹的非常詳細(xì),相信對(duì)大家的學(xué)習(xí)或者工作具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-04-04
Swift 3.0基礎(chǔ)學(xué)習(xí)之類與結(jié)構(gòu)體
最近在學(xué)swift 3.0,主要看的是蘋果的官方文檔,這里只是根據(jù)自己看官方文檔的理解所做的一些記錄,不是完整的翻譯,希望也對(duì)你有所幫助。下面這篇文章主要介紹了Swift 3.0基礎(chǔ)學(xué)習(xí)之類與結(jié)構(gòu)體的相關(guān)資料,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-03-03
在 Swift 中測(cè)試 UIAlertController的方法
這篇文章主要介紹了在 Swift 中測(cè)試 UIAlertController的方法的,需要的朋友可以參考下2015-10-10
Swift5中fileprivate與private的差別淺析
這篇文章主要給大家介紹了關(guān)于Swift5中fileprivate與private的差別的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Swift5具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Swift設(shè)計(jì)思想Result<T>與Result<T,?E:?Error>類型解析
這篇文章主要為大家介紹了Swift設(shè)計(jì)思想Result<T>與Result<T,?E:?Error>的類型示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
詳解Swift的switch...case語(yǔ)句中break關(guān)鍵字的用法
這篇文章主要介紹了Swift的switch...case語(yǔ)句中break關(guān)鍵字的用法,是Swift入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2016-04-04

