测试已测试 | ✓ |
语言语言 | SwiftSwift |
许可证 | MIT |
发布最后发布 | 2017年3月 |
SwiftSwift 版本 | 3.0 |
SPM支持 SPM | ✗ |
由 Leszek Slazynski 维护。
Swift 缺少 Objective-C 中的强大的键值观察(KVO)。但是,由于闭包、泛型和属性观察器的存在,在某些情况下,它允许更优雅的观察。但是,您必须明确指定什么可以被观察。
Observable-Swift 是一个 Swift 库,用于值观察(通过显式使用 Observable<T>
)和可订阅的事件(也显式,使用 Event<T>
)。虽然它并不完全等同于 “Swift 中的 KVO”(它是显式的,没有 “Keys”),但是这个名字非常有趣,所以如果您愿意,可以这样称呼它。这个库仍在开发中,就像 Swift 一样。欢迎就建议/想法或实际代码做出贡献。
Observable-Swift 由 Leszek Ślażyński(slazyk)提供,您可以在 twitter 和 github 上关注我。还可以查看我的另一个 Swift 库 SINQ,它使处理集合变得容易。
使用 Observable<T>
和相关类,您可以实现一系列使用值观察的图案。一些特性包括
+=
、-=
、<-
/^=
、^
的简洁可读语法{ oldValue:, newValue: }
、(oldValue, newValue)
或 (newValue)
的处理程序有时,你不想观察值的改变,而是其他重大的事件。在底层,Observable<T>
使用了 EventReference<ValueChange<T>>
的 beforeChange
和 afterChange
。然而,你也可以直接使用 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
当然,你可以在 class
或 struct
中拥有可观察的属性
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 ^
对于值类型(如 structs
或 tuples
),你也可以观察它们的突变
因为 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:)
。