• [转]ObservableSwift


    Cocoa 中的 KVO 提供了一个完善的属性监听与通知机制。但它的运行还是依赖于 Objective-C Runtime,在 Swift 中使用的时候就不如在 Objective-C 中那么自然。于是强大的开源社区贡献了一个叫做 ObservableSwift 的第三方库。它提供了与 KVO 差不多的监听机制,它的一大好处是完全使用 Swift 实现,不依赖于 Objective-C 运行时。

    关于属性监听机制,可以参考我们之前的两篇文章:

    漫谈 KVC 与 KVO
    KVC 与 KVO 拾遗补缺

    Observable

    ObservableSwift 通过使用 Swift 中的闭包,泛型,以及操作符重载等核心特性,构建处了一套原生于 Swift 语言的属性监听机制。 它的核心是一个叫做 Observable 的结构。 使用这个结构对我们要接听的属性或者变量进行包装,就让它们有了监听和通知的能力。 ObservableSwift 几乎可以监听任何类型的值,包括简单变量:

    var language: Observable<String> = Observable("Objc")
    language.afterChange += { print("Changed language from ($0) to ($1)") }
    language <- "Swift"

    让我们来分析一下这段代码。 首先我们使用 Observable 结构包装了一个字符串 “Objc” 并把它赋值给 language 变量。 为了表述清楚我们将 language 的类型也明确的写了出来 - Observable<String>。 接下来,language.afterChange 属性表示修改后的监听回调方法,它是一个闭包。 并且 ObservableSwift 重载了 += 操作符。 这样我们就可以像这样直接把回调通过 += 操作符赋值给 afterChange:

    language.afterChange += { print("Changed language from ($0) to ($1)") }

    两个参数 $0 和 $1 分别表示 language 变量修改前后的值。 监听声明好之后,当我们修改 language 的值的时候,监听回调就会被调用。 由于 language 是 Observable 类型的,我们不能直接给 language 赋值,而是通过 language.value 属性:

    language.value = "Swift"

    这时,命令行就会输出监听闭包中的 print 语句的内容。ObservableSwift 还提供了一个重载操作符 <-。上面给 value 赋值的语句,可以通过这个操作符更简单的表达:

    language <- "Swift"

    监听属性的改变

    除了简单值变量的监听,ObservableSwift 依然能够监听属性值的更改,我们定义一个 Person 类:

    struct Person {

    var firstName: Observable<String>
    var lastName: Observable<String>

    init(firstName: String, lastName: String) {

    self.firstName = Observable(firstName)
    self.lastName = Observable(lastName)

    }

    }

    这个类声明了两个属性,都用 Observable 包装。并提供了一个构造方法,用于将传递进来的 String 类型用 Observable 包装好,然后赋值给相应的属性。

    然后就可以给这些属性添加监听器了:

    var labelFirstName = UILabel(frame: CGRectMake(0, 0, 0, 0))
    var labelLastName = UILabel(frame: CGRectMake(0, 0, 0, 0))

    var p = Person(firstName: "peter", lastName: "cook")

    p.firstName.afterChange += { old,new in

    labelFirstName.text = new

    }

    p.lastName.afterChange += { old,new in

    labelLastName.text = new

    }

    可以看到,这里给 firstName 和 lastName 分别添加了 afterChange 监听闭包,这次我们把闭包的参数明确的列举了出来, old 和 new 分别代表修改前后的值。在 Person 的属性值改变的时候,更新了相应的 UILabel 的显示。这个在日常的开发中应用还是挺多的。

    监听属性改变之前的通知

    除了可以在属性更改之后提供监听闭包,当然还可以在属性修改之前也提供监听闭包,做法也很简单:

    p.firstName.beforeChange += { old,new in

    print("will Change (new)")

    }

    Observable 同样提供了 beforeChange 属性,可以完成这样的需求。

    对 struct 本身进行监听

    ObservableSwift 提供的监听机制更加原生于 Swift。它也可以监听结构(struct), 元组(tuple) 等大多数 Swift 中的类型。比如我们刚刚定义的 Person 类本身,也是可以进行监听的:

    var observablePerson = Observable(Person(firstName: "peter", lastName: "cook"))
    observablePerson.afterChange += { old,new in

    print("person changed to (new.firstName.value) (new.lastName.value)")

    }

    observablePerson.value.firstName <- "swift"

    这次用 Observable 将 Person 的初始化进行了包装,所以这个 Person 的实例也有了监听能力。可以给它添加 afterChange 监听闭包。这样,Person 实例的任何属性被更改,这个闭包都会被调用。

    删除监听器

    Observable 结构也提供了删除监听器的方法,并重载了 -= 操作符,非常方便的可以删除监听器:

    let observer = observablePerson.afterChange += { old, new in
    }

    observablePerson.afterChange -= observer

    keyPath

    ObservableSwift 同样也提供了 keyPath 的能力(可以遍历属性的属性)。不过结构稍微复杂一些:

    struct Address {

    var city: Observable<String>
    var street: Observable<String>

    init(city: String, street: String) {

    self.city = Observable(city)
    self.street = Observable(street)

    }

    }

    struct PersonWithAddress {

    var firstName: Observable<String>
    var lastName: Observable<String>

    var address: Observable<Address>

    init(firstName: String, lastName: String, address: Address) {

    self.firstName = Observable(firstName)
    self.lastName = Observable(lastName)
    self.address = Observable(address)

    }

    }

    现在 Person 又添加了一个 Address 属性, Address 本身也包含属性,如果需要监听 person.address.steet 这个属性的更改,可以这样做:

    var person = PersonWithAddress(firstName: "peter", lastName: "cook", address: Address(city: "Beijing", street: "Road"))

    chain(person.address).to{ $0.street }.afterChange += { old,new in

    print("street changed from (old) to (new)")

    }

    person.address.value.street <- "New Street"

    通过调用 chain 和 to 两个函数的调用,将属性包装成可链接的,到最后需要监听的属性添加它的 afterChange 监听闭包。 这样就可以在 street 属性更改的时候发送监听通知。

    总结

    ObservableSwift 为我们提供了一套 Swift 原生的属性监听和通知的机制。 它的好处也是因为原生,不用依赖于 Objective-C Runtime,这样在写程序的时候就不必为了实现 KVO 监听来集成 NSObject 了,也不用声明 dynamic 关键字。

    当然 ObservableSwift 也有自身的不足,由于我们必须对要监听的属性使用 Observable 结构进行包装,它会对我们的代码有一定的侵入性,并且给属性赋值的时候要使用 value 或者 <- 操作符,也会导致一些操作上的不便。

    无论使用哪种方案,都有个自己的优点与局限,这就需要你根据自己的项目来规划。 ObservableSwift 目前还处于继续开发阶段,你可以访问它的 GitHub 主页 https://github.com/slazyk/Observable-Swift 来安装并使用,甚至还可以参与它的开发过程,贡献自己的想法与实现。

    建议大家使用 Carthage 构建系统来安装它,关于 Carthage 的使用大家可以看这里:

    Carthage 包管理工具,另一种敏捷轻快的 iOS & MAC 开发体验

    最后,关于这里所列出的示例代码,大家也可以到我们的 Github 页面上面找到:https://github.com/swiftcafex/ObservableSwiftSamples

    转自:http://www.swiftmi.com/articles/913.html

  • 相关阅读:
    获取系统环境变量
    改变系统提示信息
    获取任务栏大小
    获取系统启动后经过的时间
    获取系统版本号
    z-tree的使用
    vue学习-day05 -- 案例:名字合并(监听data数据的改变)
    vue学习-day04(路由)
    eclipse在线安装ermaster插件
    vue学习-day03(动画,组件)
  • 原文地址:https://www.cnblogs.com/linganxiong/p/5897008.html
Copyright © 2020-2023  润新知