53-Swift 之 KVO (Key-Value Observing )

一 、 KVO 的概述

  • KVO 的全稱 " Key-Value Observing "

  • KVO 是鍵值觀察機(jī)制,使得當(dāng)某個(gè)對象特定的屬性發(fā)生改變時(shí)能夠通知到別的對象。這經(jīng)常用于模型和控制器之間的通信。

  • KVO 的主要的優(yōu)點(diǎn)是你不需要在每次屬性改變時(shí)手動(dòng)去發(fā)送通知。并且它支持為一個(gè)屬性注冊多個(gè)觀察者。

二 、KVO 的使用條件

  • 被觀察的對象,必須準(zhǔn)守鍵值編碼。

  • 目前 KVO 支持的類型是 NSObject 。

  • 被觀察的類能夠發(fā)出屬性改變的 KVO 的通知。

  • 被監(jiān)控的類的屬性要使用 dynamic 來修飾。否則將不會(huì)調(diào)用下面方法:

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
  • 被觀察的類要強(qiáng)引用,不能清除。

三 、 KVO 的注冊觀察者的方法及參數(shù)介紹

open func addObserver(_ observer: NSObject, forKeyPath keyPath: String, options: NSKeyValueObservingOptions = [], context: UnsafeMutableRawPointer?)

1、該方法的參數(shù)介紹

  • observer : 一個(gè)注冊的KVO 對象,必須滿足 KVC 編碼特性。

  • keyPath : 一個(gè)注冊的關(guān)鍵路徑,不能為空。

  • options : 指定包含在觀察是什么通知。

  • context : 這個(gè)參數(shù)可以是一個(gè) C 指針或者是一個(gè) 對象引用,它可以作為這個(gè)context的唯一標(biāo)識,也可以提供一些數(shù)據(jù)給觀察者。

?

2、NSKeyValueObservingOptions 的取值介紹

  • initial : 在注冊觀察者的方法 return 的時(shí)候就發(fā)出一次通知。

  • new :表示Options里面有新的值時(shí),發(fā)送一次通知。

  • old : 表示Options里面含所有屬性變化前的值。

  • prior : 會(huì)在值發(fā)生改變前發(fā)出一次通知,當(dāng)然改變后的通知依舊還會(huì)發(fā)出,也就是每次change都會(huì)有兩個(gè)通知。

四 、 KVO 響應(yīng)觀察者的方法及參數(shù)的介紹

override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)

該方法的參數(shù)介紹

  • keyPath : 注冊觀察者時(shí)的關(guān)鍵路徑。

  • object : 被注冊觀察者的對象。

  • change : change 是一個(gè)字典,它里面包含了的信息由注冊時(shí)的 options 決定。

  • context : 這個(gè)參數(shù)可以是一個(gè) C 指針或者是一個(gè) 對象引用,它可以作為這個(gè)context的唯一標(biāo)識,也可以提供一些數(shù)據(jù)給觀察者。

五、 KVO 的注銷方法及參數(shù)介紹

open func removeObserver(_ observer: NSObject, forKeyPath keyPath: String, context: UnsafeMutableRawPointer?)

或者

open func removeObserver(_ observer: NSObject, forKeyPath keyPath: String)

參數(shù)的介紹

  • observer :注冊的觀察者。

  • keyPath : 注冊觀察者時(shí)的關(guān)鍵路徑。

  • context :一個(gè)在注冊觀察者時(shí)的一個(gè) C 指針或者是一個(gè) 對象引用,它可以作為這個(gè)context的唯一標(biāo)識,也可以提供一些數(shù)據(jù)給觀察者。

六、 KVO 的使用舉例

1> 我們首先創(chuàng)建一個(gè) Person 類。

/**
 創(chuàng)建一個(gè)類
 */
class Person : NSObject{
    dynamic var name : String?
    var firstName : String?
    var lastName : String?
    /**
     獲取用戶的名字
     */
    func getPersonName() -> String {
        name = firstName! + lastName!
        return name!
    }
    /**
     反初始化
     */
    deinit {
        print("反初始化完成")
    }
}

2> 注冊觀察者

/**
 創(chuàng)建一個(gè)類
 */
NewPerson = Person.init()
/**
 開始注冊觀察者
 */
NewPerson.addObserver(self, forKeyPath: "name", options: .new, context: &NewContext)
NewPerson.firstName = "周"
NewPerson.lastName = "NetWork小賤"
/**
 獲取名字
 */
let NewName = NewPerson.getPersonName()
MyName = NewName

3> 觀察者的響應(yīng)事件

/**
 觀察者方法的實(shí)現(xiàn)
 */
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
    if keyPath=="name" {
        print("sss")
        print(object!)
        print(context!)
        print(change!)
    }else{
        super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context)
    }
}

4> 當(dāng)我們觀察的類不存在該屬性的異常處理

如果Person 類中沒有我們要設(shè)定的這個(gè)屬性,則 KVC 也無法找到這個(gè)屬性值,這時(shí)候 KVC 協(xié)議其實(shí)會(huì)調(diào)用 valueForUndefinedKey 方法,NSObject 對這個(gè)方法的默認(rèn)實(shí)現(xiàn)是拋出一個(gè) NSUndefinedKeyException 異常。

該異常的解決方法

/**
 沒有key時(shí)的異常處理
 */
override func value(forUndefinedKey key: String) -> Any? {
     return ""
}

則最使用的方法是在觀察類中加入上面的方法,則觀察類的寫法如下:

/**
 創(chuàng)建一個(gè)類
 */
class Person : NSObject{
    dynamic var name : String?
    var firstName : String?
    var lastName : String?
    /**
     獲取用戶的名字
     */
    func getPersonName() -> String {
        name = firstName! + lastName!
        return name!
    }
    
    /**
     沒有key時(shí)的異常處理
     */
    override func value(forUndefinedKey key: String) -> Any? {
         return ""
    }
    
    /**
     反初始化
     */
    deinit {
        print("反初始化完成")
    }
}

七 、屬性觀察器的介紹(再次介紹)

1> 介紹

???????屬性觀察器相當(dāng)于內(nèi)建的KVO,監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時(shí)候都會(huì)調(diào)用屬性觀察器,甚至新的值和現(xiàn)在的值相同的時(shí)候也不例外??梢詾槌搜舆t存儲屬性之外的其他存儲屬性添加屬性觀察器,也可以通過重載屬性的方式為繼承的屬性(包括存儲屬性和計(jì)算屬性)添加屬性觀察器。

2> 屬性檢查其的檢測方式

  • willSet在設(shè)置新的值之前調(diào)用。

  • didSet在新的值被設(shè)置之后立即調(diào)用。

注釋
willset觀察器會(huì)將新的屬性值作為固定參數(shù)傳入,在willSet的實(shí)現(xiàn)代碼中可以為這個(gè)參數(shù)指定一個(gè)名稱,如果不指定則參數(shù)仍然可用,這時(shí)使用默認(rèn)名稱newValue表示。類似地,didSet觀察器會(huì)將舊的屬性值作為參數(shù)傳入,可以為該參數(shù)命名或者使用默認(rèn)參數(shù)名oldValue。

注意
willSet和didSet觀察器在屬性初始化過程中不會(huì)被調(diào)用,它們只會(huì)當(dāng)屬性的值在初始化之外的地方被設(shè)置時(shí)被調(diào)用。

3> 舉例介紹

/**
 屬性觀察器
 */
func attributeViewer() -> Void {
    var PersonCount:Int = 0 {
        
        willSet(newValue){
            print("新人數(shù)是:" + "\(newValue)" + "個(gè)")
        }
        
        didSet(oldValue){
            print("老人數(shù)是:" + "\(oldValue)" + "個(gè)")
        }
    }
    
    /**
     測試
     */
    
    PersonCount = 10  
}

測試結(jié)果圖

ACC041EB-F4D8-4EC2-8438-011619B428B5.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,569評論 19 139
  • 或者KVO,是一個(gè)非正式協(xié)議,它定義了對象之間觀察和通知狀態(tài)改變的通用機(jī)制。 基本使用 使用KVO必須要滿足的條件...
    一枚iOS程序猿閱讀 819評論 0 0
  • 上半年有段時(shí)間做了一個(gè)項(xiàng)目,項(xiàng)目中聊天界面用到了音頻播放,涉及到進(jìn)度條,當(dāng)時(shí)做android時(shí)候處理的不太好,由于...
    DaZenD閱讀 3,101評論 0 26
  • ??KVO簡介:鍵值觀察,是基于鍵值編碼(KVC)的一種觀察模式。 是iOS中常用的一種消息傳遞機(jī)制。??對接模...
    西葉lv閱讀 532評論 0 2
  • [深入淺出Cocoa]詳解鍵值觀察(KVO)及其實(shí)現(xiàn)機(jī)理羅朝輝 (http://www.cppblog.com/k...
    Crazy2015閱讀 760評論 0 1

友情鏈接更多精彩內(nèi)容