ReactiveSwift(下)

SignalProducer

SignalProducer是ReactiveSwift中冷信号的实现, 是第二种发送事件的途径.

        热信号是活动着的事件发生器, 相对应的, 冷信号则是休眠中的事件发生器. 也就是说冷信号需要一个唤醒操作, 然后才能发送事件, 而这个唤醒操作就是订阅它. 因为订阅后才发送事件, 显然, 冷信号不存在时机早晚的问题. 仍以春晚举例:

        冷信号相当于春晚的视频文件而不是现场直播, 正常情况下, 视频文件肯定是不会自动播放的, 但你只要一双击, 它就被启动播放然后输出节目了.

//1. 通过SignalProducer.init(startHandler: (Observer, Lifetime) -> Void)创建SignalProducer

let producer = SignalProducer { (innerObserver, lifetime) in

lifetime.observeEnded({

print("信号无效了 你可以在这里进行一些清理工作")

})

//2. 向外界发送事件

innerObserver.send(value: 1)

innerObserver.send(value: 2)

innerObserver.sendCompleted()

}

//3. 创建一个观察者封装事件处理逻辑

let outerObserver = Signal.Observer(value: { (value) in

print("did received value: (value)")

})

//4. 添加观察者到SignalProducer

producer.start(outerObserver)

输出: did received value: 1

did received value: 2

信号无效了 你可以在这里进行一些清理工作


typealias Producer = ReactiveSwift.SignalProducer

let producer = Producer { (innerObserver, _) in

//没什么想清理的

innerObserver.send(value: 1)

innerObserver.send(value: 2)

innerObserver.sendCompleted()

}

producer.startWithValues { (value) in

print("did received value: (value)")

}

producer.startWithFailed(action: )

producer.startWithResult(action: )

producer.startWithXXX...各种便利函数

和Signal的订阅方式如出一辙, 只是名字换了一下, Signal.observeXXX换成了SignalProducer.startXXX.


            都是事件发生器, 所以API方面Signal和SignalProducer都是一样的,上面的map, on, merge, comblinelast...等等, SignalProducer也有一份, 作用也都一样, 我就不多说了, 这里简单给两段代码说说可能遇到的坑

func fetchData(completionHandler: (Int, Error?) -> ()) {

print("发起网络请求")

completionHandler(1, nil)

}

let producer = Producer {[unowned self] (innerObserver, _) in

self.fetchData(completionHandler: { (data, error) in

innerObserver.send(value: data)

innerObserver.sendCompleted()

})

}

producer.startWithValues { (value) in

print("did received value: (value)")

}

producer.startWithValues { (value) in

print("did received value: (value)")

}

输出: 发起网络请求

did received value: 1

发起网络请求

did received value: 1


也许你只是想两个观察者共享一次网络请求带回的Event, 但事实上这里会发生两次网络请求, 但这不是一个bug, 这是一个feature.

SignalProducer的一个特性是, 每次被订阅就会执行一次初始化时保存的闭包.

所以如果你有类似一次执行, 多处订阅的需求, 你应该选择Signal而不是SignalProducer. 所以, 符合需求的代码可能是这样:


let signalTuple = NSignal.pipe()

signalTuple.output.observeValues { (value) in

print("did received value: (value)")

}

signalTuple.output.observeValues { (value) in

print("did received value: (value)")

}

self.fetchData { (data, error) in

signalTuple.input.send(value: data)

signalTuple.input.sendCompleted()

}

输出: 发起网络请求

did received value: 1

did received value: 1

            到目前为止, 示例代码中给到的都是NoError类型的信号, 在实际开发中, 这显然是不可能的, 毕竟错误是不可避免的. 通常我们的项目会声明一个类似APIError的错误类型来表示这些错误, 所以你可能会有这样的声明:    

structAPIError: Swift.Error {

let code: Int

var reason =""

}

typealias NSignal = ReactiveSwift.Signaltypealias 

 APISignal = ReactiveSwift.Signaltypealias

 Producer = ReactiveSwift.SignalProducertypealias

 APIProducer = ReactiveSwift.SignalProducer

这样的声明很好, 能让ReactiveSwift写起来像RXSwift一样"简洁". 但这里需要加上下面的代码才能更好的工作:

extension SignalProducer where Error == APIError {

@discardableResult

func startWithValues(_ action: @escaping (Value) -> Void) -> Disposable {

returnstart(Signal.Observer(value: action))

}

}

        这是因为默认的SignalProducer是没有startWithValues函数的, ReactiveSwift会在Extension里给它加上startWithValues函数, 但是这只对NoError有效, 所以当你在自定义Error时, 请记得加上类似的代码.    

推荐阅读更多精彩内容