美文网首页花落√莫相思
53-Swift 之 KVO (Key-Value Observ

53-Swift 之 KVO (Key-Value Observ

作者: NetWork小贱 | 来源:发表于2017-07-28 17:56 被阅读85次

    一 、 KVO 的概述

    • KVO 的全称 " Key-Value Observing "

    • KVO 是键值观察机制,使得当某个对象特定的属性发生改变时能够通知到别的对象。这经常用于模型和控制器之间的通信。

    • KVO 的主要的优点是你不需要在每次属性改变时手动去发送通知。并且它支持为一个属性注册多个观察者。

    二 、KVO 的使用条件

    • 被观察的对象,必须准守键值编码。

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

    • 被观察的类能够发出属性改变的 KVO 的通知。

    • 被监控的类的属性要使用 dynamic 来修饰。否则将不会调用下面方法:

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?)
    
    • 被观察的类要强引用,不能清除。

    三 、 KVO 的注册观察者的方法及参数介绍

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

    1、该方法的参数介绍

    • observer : 一个注册的KVO 对象,必须满足 KVC 编码特性。

    • keyPath : 一个注册的关键路径,不能为空。

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

    • context : 这个参数可以是一个 C 指针或者是一个 对象引用,它可以作为这个context的唯一标识,也可以提供一些数据给观察者。

     

    2、NSKeyValueObservingOptions 的取值介绍

    • initial : 在注册观察者的方法 return 的时候就发出一次通知。

    • new :表示Options里面有新的值时,发送一次通知。

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

    • prior : 会在值发生改变前发出一次通知,当然改变后的通知依旧还会发出,也就是每次change都会有两个通知。

    四 、 KVO 响应观察者的方法及参数的介绍

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

    该方法的参数介绍

    • keyPath : 注册观察者时的关键路径。

    • object : 被注册观察者的对象。

    • change : change 是一个字典,它里面包含了的信息由注册时的 options 决定。

    • context : 这个参数可以是一个 C 指针或者是一个 对象引用,它可以作为这个context的唯一标识,也可以提供一些数据给观察者。

    五、 KVO 的注销方法及参数介绍

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

    参数的介绍

    • observer :注册的观察者。

    • keyPath : 注册观察者时的关键路径。

    • context :一个在注册观察者时的一个 C 指针或者是一个 对象引用,它可以作为这个context的唯一标识,也可以提供一些数据给观察者。

    六、 KVO 的使用举例

    1> 我们首先创建一个 Person 类。

    /**
     创建一个类
     */
    class Person : NSObject{
        dynamic var name : String?
        var firstName : String?
        var lastName : String?
        /**
         获取用户的名字
         */
        func getPersonName() -> String {
            name = firstName! + lastName!
            return name!
        }
        /**
         反初始化
         */
        deinit {
            print("反初始化完成")
        }
    }
    

    2> 注册观察者

    /**
     创建一个类
     */
    NewPerson = Person.init()
    /**
     开始注册观察者
     */
    NewPerson.addObserver(self, forKeyPath: "name", options: .new, context: &NewContext)
    NewPerson.firstName = "周"
    NewPerson.lastName = "NetWork小贱"
    /**
     获取名字
     */
    let NewName = NewPerson.getPersonName()
    MyName = NewName
    

    3> 观察者的响应事件

    /**
     观察者方法的实现
     */
    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> 当我们观察的类不存在该属性的异常处理

    如果Person 类中没有我们要设定的这个属性,则 KVC 也无法找到这个属性值,这时候 KVC 协议其实会调用 valueForUndefinedKey 方法,NSObject 对这个方法的默认实现是抛出一个 NSUndefinedKeyException 异常。

    该异常的解决方法

    /**
     没有key时的异常处理
     */
    override func value(forUndefinedKey key: String) -> Any? {
         return ""
    }
    

    则最使用的方法是在观察类中加入上面的方法,则观察类的写法如下:

    /**
     创建一个类
     */
    class Person : NSObject{
        dynamic var name : String?
        var firstName : String?
        var lastName : String?
        /**
         获取用户的名字
         */
        func getPersonName() -> String {
            name = firstName! + lastName!
            return name!
        }
        
        /**
         没有key时的异常处理
         */
        override func value(forUndefinedKey key: String) -> Any? {
             return ""
        }
        
        /**
         反初始化
         */
        deinit {
            print("反初始化完成")
        }
    }
    
    

    七 、属性观察器的介绍(再次介绍)

    1> 介绍

           属性观察器相当于內建的KVO,监控和响应属性值的变化,每次属性被设置值的时候都会调用属性观察器,甚至新的值和现在的值相同的时候也不例外。可以为除了延迟存储属性之外的其他存储属性添加属性观察器,也可以通过重载属性的方式为继承的属性(包括存储属性和计算属性)添加属性观察器。

    2> 属性检查其的检测方式

    • willSet在设置新的值之前调用。

    • didSet在新的值被设置之后立即调用。

    注释
    willset观察器会将新的属性值作为固定参数传入,在willSet的实现代码中可以为这个参数指定一个名称,如果不指定则参数仍然可用,这时使用默认名称newValue表示。类似地,didSet观察器会将旧的属性值作为参数传入,可以为该参数命名或者使用默认参数名oldValue。

    注意
    willSet和didSet观察器在属性初始化过程中不会被调用,它们只会当属性的值在初始化之外的地方被设置时被调用。

    3> 举例介绍

    /**
     属性观察器
     */
    func attributeViewer() -> Void {
        var PersonCount:Int = 0 {
            
            willSet(newValue){
                print("新人数是:" + "\(newValue)" + "个")
            }
            
            didSet(oldValue){
                print("老人数是:" + "\(oldValue)" + "个")
            }
        }
        
        /**
         测试
         */
        
        PersonCount = 10  
    }
    

    测试结果图

    ACC041EB-F4D8-4EC2-8438-011619B428B5.png

    相关文章

      网友评论

        本文标题:53-Swift 之 KVO (Key-Value Observ

        本文链接:https://www.haomeiwen.com/subject/rvqflxtx.html