美文网首页iOS Tips
ReactiveSwift框架分析1 — Signal 和 Ob

ReactiveSwift框架分析1 — Signal 和 Ob

作者: 沈枫_ShenF | 来源:发表于2019-05-31 23:40 被阅读0次

    为什么用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<Int, NoError>.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<Int, NoError>.pipe()
    

    通过pipe()方法,创建一个‘管道’,这个‘管道’其实是个元组,元素output代表输出端,类型为Signal <Int,NoError> , 元素input代表输入端,类型为Observer <Int,NoError>,作为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<Int, NoError>.Observer (
    value: { value in
        print("Time elapsed = \(value)")
    }, 
    completed: { print("completed") },
    interrupted: { print("interrupted") })
    output.observe(signalObserver)
    

    完整的代码如下:

    //Create an observer
    let signalObserver = Signal<Int, NoError>.Observer(
    value: { value in
        print("Time elapsed = \(value)")
    }, completed: { 
        print("completed") 
    }, interrupted: { 
        print("interrupted") 
    })
    //Create an a signal
    let (output, input) = Signal<Int, NoError>.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<Bool, NoError>.Observer(value: { value in
         button.isEnabled = value
    })
    let disposable = transformedSignal.observe(observer)
    

    第4步:停止观察信号

    disposable?.dispose()
    

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

    以上整个过程是:

    //Defining consumer
    let observer = Signal<Bool, NoError>.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 和 Ob

        本文链接:https://www.haomeiwen.com/subject/qwemtctx.html