有很多在给人介绍Reactive的几个开源项目(ReactiveCocoa, RxSwift)的使用,我就不想在这个方面写什么了。我是一个实践主义者,所以我从我的角度来谈谈这种方案:解决了什么样的问题,怎么实现的,以及适合应用的场景。同时也加深自己对Reactive的理解。
这里我们来看看是怎么实现的,关于pure function
和monad
的部分我也不准备介绍了,毕竟我在这方面还不是特别熟悉。
signal observer
首先我们来想一下一个最简单信号的流程。当一个信号被订阅时(subscribe),发出信号后会触发订阅者(observer)执行下一步(sendNext)。那么一个最简单的信号(signal)和订阅者(observer)的协议就如下。
protocol Observer {
func send(next: AnyObject)
func send(error: NSError)
func sendComplete()
}
protocol Signal {
func subscribe(_ observer: �Observer)
}
那么现在实现一个最简单的UIButton的信号。
class ButtonSignal: Signal {
var observer: Observer?
init(button: UIButton) {
button .addTarget(self, action: #selector(onButton(sender:)), for: .touchUpInside)
}
@objc func onButton(sender: UIButton) {
self.observer?.send(next: sender)
}
func subscribe(_ observer: Observer) {
self.observer = observer
}
}
class ButtonSignal: Signal {
var observer: Observer?
init(button: UIButton) {
button .addTarget(self, action: #selector(onButton(sender:)), for: .touchUpInside)
}
func onButton(sender: UIButton) {
self.observer?.send(next: sender)
}
func subscribe(_ observer: Observer) {
self.observer = observer
}
}
然后实现一个最简单的订阅者。
class ButtonObserver: Observer {
func send(next: AnyObject) {
print("send next!")
}
func sendComplete() {
print("send complete")
}
func send(error: NSError) {
print("send \(error)")
}
}
最后连接起来
signal = ButtonSignal(button: button)
signal?.subscribe(ButtonObserver())
那么问题来了,难道我们要为每个信号都创建一个类吗。当然不是,我们可以创建一个通用的信号和订阅者。
class BlockSignal: Signal {
typealias CreateBlock = (Observer)->Void
var block: CreateBlock
init(block:@escaping CreateBlock) {
self.block = block
}
func subscribe(_ observer: Observer) {
self.block(observer)
}
}
class BlockObserver: Observer {
var next: (AnyObject)->Void
var complete: ()->Void
var error: (NSError)->Void
init(next: @escaping (AnyObject)->Void,
complete: @escaping ()->Void,
error: @escaping (NSError)->Void) {
self.next = next
self.complete = complete
self.error = error
}
@objc func send(next: AnyObject) {
self.next(next)
}
func sendComplete() {
self.complete()
}
func send(error: NSError) {
self.error(error)
}
}
同时在使用的过程时通过block来创建具体信号。
signal = BlockSignal(block: { (observer) in
self.button.addTarget(observer,
action: #selector(BlockObserver.send(next:)),
for: .touchUpInside)
})
observer = BlockObserver(next: { (sender) in
print("send next!")
}, complete: {
print("send complete")
}) { (error) in
print("send error")
}
signal?.subscribe(observer!)
以上就是最简单的信号量和订阅者实现。这里为了简洁的说明问题,所以没有考虑到内存方面的问题。
dispose
上节说了内存方面的问题。还有一个问题就是如何取消订阅呢。那么这里需要有模块负责释放(dispose)。
那么将接口改为
protocol Disposable {
func dispose()
}
protocol Signal {
func subscribe(_ observer: Observer) -> Disposable
}
实现也按照block形式
class BlockDisposable: Disposable {
var block: ()->Void
init(block: @escaping ()->Void) {
self.block = block
}
func dispose() {
self.block()
}
}
class BlockSignal: Signal {
func subscribe(_ observer: Observer) -> Disposable {
return self.block(observer)
}
}
使用时和上面基本一致
signal = BlockSignal(block: { (observer) in
self.button.addTarget(observer,
action: #selector(BlockObserver.send(next:)),
for: .touchUpInside)
return BlockDisposable(block: {
self.button.removeTarget(observer,
action: #selector(BlockObserver.send(next:)),
for: .touchUpInside)
})
})
需要解除订阅的时候
self.disposable = signal?.subscribe(observer!)
self.disposable?.dispose()
之后
到目前为止,可以说signal-observer部分已经完全实现了。
其中冷信号和热信号也非常简单
protocol Subject: Observer, Signal {}
Scheduler也比较简单,将执行放到对应的队列中即可。
下篇结合我的角度来聊聊应用场景。