美文网首页
在swift中实现KVO的思路

在swift中实现KVO的思路

作者: fuadam1982 | 来源:发表于2016-12-02 14:52 被阅读82次

    我们知道如果不借助NSObject基类是无法实现oc中的KVO的。而KVO的基本原理是很简单的,把每次对属性的get、set转发给订阅者就可以了。但是如果没有编译器和runtime的支持仅使用swift的语法,实际�使用起来还是很不方便的(其实同样的问题在java、c#中早已有之)。一个简单的解决方案是定义一个observable接口去桥接属性的get\set方法与该类外部的订阅者(参考windows phone做MVVM的方式)。

    我目前想到的折中解决方案是这样的:

    1. 利用上篇提到的"关联对象"将对一个属性的get/set 转发到自定义的KVO属性对象上

    2. 在类的外部利用属性名字符串进行订阅,但为了类型安全代码写起来有点复杂(obj和propName都重复使用了2次)。伪代码类似于这样:

       kvo(obj, obj.propName, "propName") { newValue in
           // callback
       }
      

    在这里不得不说oc中的宏定义(参见RACObserve宏)和c#中的expression语法才是解决这类问题(自定义DSL)的利器。但是swift中并没有这些,甚至都不能通过反射获取属性的get、set方法。虽然在oc中也是使用字符串来关联待观察的字段,但是在swift中这么用总是觉得有点别扭。而我实际上想要的是这个样的:

    kvo(obj.propName) {newValue in 
         callback
    }
    

    在现有的swift语法中是无法实现的,所以我想用个技巧来解决这个问题:

    1. 在obj实例上关联一个计数检查字段,假设是:checkNum

    2. 在kvo函数中,调用 autoclosure { obj.propName }。

    3. 每次访问propName的时候,执行atomicIncrement(CheckNum)

    4. 在autoclosure { obj.propName } 执行后,进行判断:

       // 伪代码
       while (true) {
           if CAS(oldCheckNum, checkNum, 1) == 1 {
               // 关联当前propName与callback
           } else {
               // 重置checkNum,并且重新调用propName
            }
       }
      

    因为是针对每个实例对象进行检查,且是lock-free的,所以性能不会有问题。可惜的是Atomic系列API都已经deprecated,因此只能用GCD实现了。虽然性能差一些,但KVO行为本身就是异步的,也算是可以接受了。

    相关文章

      网友评论

          本文标题:在swift中实现KVO的思路

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