Observable-Swift 0.7.0

Observable-Swift 0.7.0

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布最后发布2017年3月
SwiftSwift 版本3.0
SPM支持 SPM

Leszek Slazynski 维护。



Swift 的值观察和事件

Swift 缺少 Objective-C 中的强大的键值观察(KVO)。但是,由于闭包、泛型和属性观察器的存在,在某些情况下,它允许更优雅的观察。但是,您必须明确指定什么可以被观察。

概述

Observable-Swift 是一个 Swift 库,用于值观察(通过显式使用 Observable<T>)和可订阅的事件(也显式,使用 Event<T>)。虽然它并不完全等同于 “Swift 中的 KVO”(它是显式的,没有 “Keys”),但是这个名字非常有趣,所以如果您愿意,可以这样称呼它。这个库仍在开发中,就像 Swift 一样。欢迎就建议/想法或实际代码做出贡献。

Observable-Swift 由 Leszek Ślażyński(slazyk)提供,您可以在 twittergithub 上关注我。还可以查看我的另一个 Swift 库 SINQ,它使处理集合变得容易。

可观察对象

使用 Observable<T> 和相关类,您可以实现一系列使用值观察的图案。一些特性包括

  • 可观察的变量和属性
  • 可观察对象的链式调用(也称为键路径观察)
  • 使用 +=-=<-/^=^ 的简洁可读语法
  • 对于不喜欢自定义操作符的人来说,有另一种语法
  • 用于 更改之前更改之后 的处理程序
  • 用于 { oldValue:, newValue: }(oldValue, newValue)(newValue) 的处理程序
  • 为每个可观察对象添加多个处理程序
  • 移除/使处理程序无效
  • 绑定到观察者生命周期的处理程序
  • 值类型(结构体、元组等)的 可观察对象突变
  • 从可观察对象到基础类型的转换(自 Swift Beta 6 起不可用)
  • 组合其他可观察对象的可观察对象
  • 作为值类型或引用类型的可观察对象
  • ...

事件

有时,你不想观察值的改变,而是其他重大的事件。在底层,Observable<T> 使用了 EventReference<ValueChange<T>>beforeChangeafterChange。然而,你也可以直接使用 Event<T>EventReference<T> 并实现其他事件。

安装

你可以使用 CocoaPods 或 Carthage 来安装 Observable-Swift。

否则,在项目中使用 Observable-Swift 的一种简单方法是将此仓库克隆到本地,并将 Observable-Swift.xcodeproj 添加到项目中/workspace,然后将 Observable.framework 添加到你的目标框架中。

之后,只需 import Observable

例子

Observable<T> 是一个简单的 struct,它允许你拥有可观察的变量。

// create a Observable<Int> variable
var x = Observable(0)

// add a handler
x.afterChange += { println("Changed x from \($0) to \($1)") }
// without operators: x.afterChange.add { ... }

// change the value, prints "Changed x from 0 to 42"
x <- 42
// alternativelyL x ^= 42, without operators: x.value = 42

当然,你可以在 classstruct 中拥有可观察的属性

struct Person {
    let first: String
    var last: Observable<String>

    init(first: String, last: String) {
        self.first = first
        self.last = Observable(last)
    }
}

var ramsay = Person(first: "Ramsay", last: "Snow")
ramsay.last.afterChange += { println("Ramsay \($0) is now Ramsay \($1)") }        
ramsay.last <- "Bolton"

在 Swift Beta 5 之前,你可以隐式地将 Observable<T> 转换为 T,并在预期 T 的位置使用它。不幸的是,Beta 6 禁止定义隐式转换

let x = Observable(20)
// You can use the value property ...
let y1 = x.value + 22
// ... or a postfix operator ...
let  y2 = x^ + 22
/// ... which has the advantage of easy chaining
let y3 = obj.property^.whatever^.sthElse^
/// ... you can also use ^= instead of <- for consistency with the postfix ^

对于值类型(如 structstuples),你也可以观察它们的突变
因为 Observable 是一个 struct,所以在示例中 ramsay 也会被突变。这意味着,你也可以观察 ramsay。

struct Person {
    let first: String
    var last: String
    var full: String { get { return "\(first) \(last)" } }
}

var ramsay = Observable(Person(first: "Ramsay", last: "Snow"))
// x += { ... } is the same as x.afterChange += { ... }
ramsay += { println("\($0.full) is now \($1.full)") }
ramsay.value.last = "Bolton"

你可以通过保留订阅对象来移除观察者

var x = Observable(0)    
let subscr = x.afterChange += { (_,_) in println("changed") }
// ...
x.afterChange -= subscr
// without operators: x.afterChange.remove(subscr)

或使它失效

var x = Observable(0)    
let subscr = x.afterChange += { (_,_) in println("changed") }
// ...
subscr.invalidate() // will be removed next time event fires

或将订阅绑定到对象的生命周期

var x = Observable(0)        
for _ in 0..1 {
    let o = NSObject() // in real-world this would probably be self
    x.afterChange.add(owner: o) { (oV, nV) in println("\(oV) -> \(nV)") }
    x <- 42 // handler called
} // o deallocated, handler invalidated
x <- -1 // handler not called

你还可以链式调用可观察对象(观察 "键路径")

class Person {
    let firstName: String
    var lastName: Observable<String>
    var friend: Observable<Person?> = Observable(nil)
    // init(...) { ... }
}

let me = Person()
var myFriendsName : String? = nil

// we want to observe my current friend last name
// and get notified with name when the friend or the name changes
chain(me.friend).to{$0?.lastName}.afterChange += { (_, newName) in
    myFriendsName = newName
}

// alternatively, we can do the same with '/' operator
(me.friend / {$0?.lastName}).afterChange += { (_, newName) in
    myFriendsName = newName
}

Event<T> 是一个简单的 struct,它允许你定义可订阅的事件。`Observable<T>` 对 `afterChange` 和 `beforeChange` 使用了 `EventReference<ValueChange<T>>`。

class SomeClass {
    // defining an event someone might be interested in
    var somethingChanged = Event<String>()

    // ...

    func doSomething() {
        // ...
        // fire the event and notify all observers
        somethingChanged.notify("Hello!")
        // ...
    }
}

var obj = SomeClass()

// subscribe to an event
obj.somethingChanged += { println($0) }

obj.doSomething()

更多的例子可以在 ObservableTests.swift 的测试中找到

高级

如果你需要使用引用类型的可观察对象,你可以使用 ObservableProxy,它位于你的代码和真实的 Observable 值类型之间,这是一个引用类型。你也可以使用 ObservableReference,它是一个 ObservableProxy,它持有 Observable 的属性。

对于 Event 也是如此,同样存在 EventReference。实际上,`Observable` 使用了 EventReference 而不是 Event,否则一些用例将难以实现。这意味着,如果你想取消共享事件和订阅,你需要调用 observable.unshare(removeSubscriptions:)