ReactiveSwift框架分析1 — Signal 和 Observer

为什么用ReactiveSwift?

先看个例子,假设我们想要实现一个用户界面,其中包含一个UILabel (让我们称之为label )和一个UITextView (让我们称之为textView ),其中UILabel需要实时地显示出在UITextView中输入的文本。 为了实现这种需求,我们一般会监听textView的代理方法:

func textViewDidChange(_ textView: UITextView) { 
  label.text = textView.text 
 }

而在ReactiveSwift,我们可以很优雅地让label的text跟textView的text实时保持一致:

label.reactive.text <~ textView.reactive.continuousTextValues

简简单单地通过操作符<〜,就将label的text跟textView的text进行了绑定,label的文本会在label的整个生命周期中与textView的文本等同。

<〜称为操作符(binding operator),操作符的左侧是绑定目标(binding target) ,右侧是绑定源(binding source)。

再来看一个例子:

usernameTextField.reactive.continuousTextValues.observeValues {
    text in
            
    print(text ?? "")
 }

随着username text field输入,你在Xcode控制台会看到以下输出:

e
ee
eef
eeff
eefff
eeffff
eefffff
eeffffff

每次你在username text field输入,控制台都会输出,而不用设置target-action,也不用设置委托(delegate)。

ReactiveCocoa信号会发送一系列的事件给订阅者(观察者)。ReactiveCocoa有以下事件:

  • Value事件:Value事件提供了新值
  • Failed事件:Failed事件表明在信号完成之前发生了错误
  • Completed事件:Completed事件信号完成了,之后不会再有新的值发送
  • Interrupted事件:Interrupted事件表明由于被取消,信号被终止了

usernameTextField.reactive就是把usernameTextField变成可响应的,而continuousTextValues就是text值的信号。通过observeValues,我们可以观察到continuousTextValues这个信号传来的Value事件,每次在usernameTextField输入的时候,我们就会接收到text的值。

如何创建一个Signal并通过Observer观察它呢?

  1. 信号Signal

信号被定义为事件流,其中每个事件表示在指定时间点上的一种状态。如我们在文本框输入的时候,它会不断地产生值类型的事件。事件event是信号的基本单位,它是一个枚举:

public enum Event {
        /// A value provided by the signal.
        case value(Value)

        /// The signal terminated because of an error. No further events will be
        /// received.
        case failed(Error)

        /// The signal successfully terminated. No further events will be received.
        case completed

        /// Event production on the signal has been interrupted. No further events
        /// will be received.
        ///
        /// - important: This event does not signify the successful or failed
        ///              completion of the signal.
        case interrupted
}
  1. 观察者Observer

在ReactiveSwift中我们可以通过Observer观察Signal发出的事件。Observer封装了一个闭包(Event) -> Void,我们可以在闭包中根据event类型进行相应的处理:

let observer = Signal.Observer { (event) in
    switch event {
    case let .value(v):
        print("value = \(v)")
    case let .failed(error):
        print("error = \(error)")
    case .completed:
        print("completed")
    case .interrupted:
        print("interrupted")
    }
}

现在,我们清楚如何创建一个Observer,接下来通过一个例子看看如何创建信号及观察信号。

要求:每隔五秒钟打印一次,持续五十秒。

信号的创建可以看作是流过管道的水流,Observer在源端不断地发送数据,将事件注入到输出端Signal,然后我们在通过跟Signal绑定一起的Observer实例观察到Signal中的value,其实整个过程就这么简单,so easy!

首先,创建信号:

let (output, input) = Signal.pipe()

通过pipe()方法,创建一个‘管道’,这个‘管道’其实是个元组,元素output代表输出端,类型为Signal , 元素input代表输入端,类型为Observer ,作为input的Observer发送数据,将事件注入output的Signal。

现在我们向信号发送值:

for i in 0..<10 {
 DispatchQueue.main.asyncAfter(deadline: .now() + 5.0 * Double(i)) {
     input.send(value: i)
 }
}

好了,信号有了,我们还需要一个Observer实例来观察信号中的事件,上面我说过,Observer封装了event的处理逻辑,现在我们需要把前面发送的值打印出来,所以我们创建了这样的一个Observer:

let signalObserver =  Signal.Observer (
value: { value in
    print("Time elapsed = \(value)")
}, 
completed: { print("completed") },
interrupted: { print("interrupted") })
output.observe(signalObserver)

完整的代码如下:

//Create an observer
let signalObserver = Signal.Observer(
value: { value in
    print("Time elapsed = \(value)")
}, completed: { 
    print("completed") 
}, interrupted: { 
    print("interrupted") 
})
//Create an a signal
let (output, input) = Signal.pipe()
//Send value to signal
for i in 0..<10 {
    DispatchQueue.main.asyncAfter(deadline: .now() + 5.0 *  Double(i)) {
  input.send(value: i)
 }
}
//Observe the signal
output.observe(signalObserver)

再来看个例子:

当文本框输入字符超过10个时,启用按钮。

第1步:创建信号

let signal = textField.reactive.continuousTextValues 

这里,在文本textfield键入的文本通过信号textField.reactive.continuousTextValues表示。

第2步:转换信号

在第一步中创建的信号会发出可选字符串。 我们可以通过运算符map将其转换成发出布尔值的信号。

 let transformedSignal = signal 
  .map {text in 
 text ??  “”} 
  .map {text in 
  text.characters.count> 10 
  } 

第3步:观察信号

接下来,我们将观察信号,并将设置按钮的isEnabled的操作封装到Observer中。

let observer = Signal.Observer(value: { value in
     button.isEnabled = value
})
let disposable = transformedSignal.observe(observer)

第4步:停止观察信号

disposable?.dispose()

当然,最好的做法是在类的deinit中释放所有观察者。

以上整个过程是:

//Defining consumer
let observer = Signal.Observer(value: { value in
    button.isEnabled = value
})
//Defining source
let signal = textField.reactive.continuousTextValues
let transformedSignal = signal
.map { text in
   text ?? "" }
.map { text in
   text.characters.count > 10
}
//Consuming signal
let disposable = transformedSignal.observe(observer)
//Limit Scope
disposable?.dispose()

小结:

让我们回顾一下,我们需要三个简单的步骤来创建一个信号并观察它:

  1. 创建一个pipe管道,同时创建了一个输入端Observer,一个输出端Signal
  2. 创建观察者,订阅Signal。
  3. 通过输入端Observer发送值给Signal,这将触发所有订阅了该信号的观察者执行与观察者关联的闭包。

你可能感兴趣的:(ReactiveSwift框架分析1 — Signal 和 Observer)