美文网首页
ReactiveSwift框架分析6 — 操作符

ReactiveSwift框架分析6 — 操作符

作者: 沈枫_ShenF | 来源:发表于2019-06-08 14:45 被阅读0次

<~操作符

<~的左边是绑定目标(BindingTargetProvider), 右边则是数据源(BindingSource), <~会把右边数据源的发送出的Value直接绑定到左边的目标上。
例如:

let errorLabel: UILabel 
let sendButton: UIButton
let phoneNumerTextField: UITextField
 
var errorText = MutableProperty("")
var validPhoneNumer = MutableProperty("")
 
errorLabel.reactive.text <~ errorText //绑定错误信息到errorLabel 
sendButton.reactive.isEnabled <~ errorText.map{ $0.count == 0 } 

sendButton.reactive.backgroundColor <~ errorText.map{ $0.count == 0 ? UIColor.red : UIColor.gray } 
phoneNumerTextField.reactive.text <~ validPhoneNumer //绑定有效输入到输入框
 

对于非现成的绑定目标,可以类比加上拓展,比如给YYLabel加个拓展:

//UILabel的默认拓展
extension Reactive where Base: UILabel {
    public var text: BindingTarget {
        return makeBindingTarget { $0.text = $1 }//$0表示UI控件本身 $1表示value
    }
     
    public var attributedText: BindingTarget {
        return makeBindingTarget { $0.attributedText = $1 }
    }
}
//给YYLabel也加上拓展
extension Reactive where Base: YYLabel {
    public var text: BindingTarget {
        return makeBindingTarget { $0.text = $1 }//$0表示UI控件本身 $1表示value
    }
     
    public var attributedText: BindingTarget {
        return makeBindingTarget { $0.attributedText = $1 }
    }
}

那<~是如何实现的呢?

public protocol BindingSource: SignalProducerConvertible {
    associatedtype Value
     
    associatedtype Error: Swift.Error
    var producer: SignalProducer { get }
}
extension Signal: BindingSource {}
extension SignalProducer: BindingSource {}
 
//绑定目标提供者
public protocol BindingTargetProvider {
    associatedtype Value
    var bindingTarget: BindingTarget { get }
}
 
//绑定目标
public struct BindingTarget: BindingTargetProvider {
 
    public let lifetime: Lifetime //这里定义何时取消订阅数据源
    public let action: (Value) -> Void //这里定义了如何利用数据源发送的Value(一般来说就是简单的用Value设置某个属性)
    ......
}
 
extension BindingTargetProvider {
    @discardableResult
    public static func <~ 
        (provider: Self, source: Source) -> Disposable?
        where Source.Value == Value, Source.Error == NoError {
        //订阅右边的数据源提供的producer, 在订阅回调中执行绑定目标的action闭包
        return source.producer
            .take(during: provider.bindingTarget.lifetime)
            .startWithValues(provider.bindingTarget.action)
    }
}

可以看出,订阅右边的数据源提供的producer,在订阅回调中执行绑定目标的action闭包。

我们看看ReactiveSwift是如何给UI控件添加BindingTarget的, 以Label举例:

public protocol ReactiveExtensionsProvider: class {}
extension ReactiveExtensionsProvider {
    public var reactive: Reactive {
        return Reactive(self)
    }
     
    public static var reactive: Reactive.Type {
        return Reactive.self
    }
     
}//任何对象获取 someObject.reactive时就返回一个Reactive结构体, Reactive.base即是someObject
 
public struct Reactive {
    public let base: Base
    fileprivate init(_ base: Base) {
        self.base = base
    }
}

extension Reactive where Base: NSObjectProtocol {
 
    //创建一个BindingTarget BindingTarget.action则是在UI线程操作value
    public func makeBindingTarget(on scheduler: Scheduler = UIScheduler(), _ action: @escaping (Base, U) -> Void) -> BindingTarget {
        return BindingTarget(on: scheduler, lifetime: lifetime) { [weak base = self.base] value in
            if let base = base {
                action(base, value)
            }
        }
    }
}
 
extension Reactive where Base: UILabel {
    //当获取label.reactive.text时 就创建一个makeBindingTarget makeBindingTarget的action则是直接设置self.text = value
    public var text: BindingTarget {
        return makeBindingTarget { $0.text = $1 }//$0即是label自己 $1即是value
    }
}

Signal常用函数

  • KVO
public func signal(forKeyPath keyPath: String) -> Signal<Any?, NoError>

KVO的Reactive版本, 对于NSObject的子类可以直接使用, 对于Swift的原生类需要加上dynamic修饰。

let tableView: UITableView
dynamic var someValue = 0

//对定义的属性KVO
reactive.signal(forKeyPath: "someValue").observeValues { [weak self] (value) in
      //code
}

//对tableView的KVO
tableView.reactive.signal(forKeyPath: "contentSize").observeValues {[weak self] (contentSize) in
    if let contentSize = contentSize as? CGSize,
        let strongSelf = self {
        
        let isHidden = contentSize.height < strongSelf.tableView.height
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now(), execute: {
            strongSelf.tableView.mj_footer.isHidden = isHidden
        })
    }
}

  • map
let (signal, innerObserver) = NSignal<Int>.pipe()
signal.map { return "xxx" + String($0) } //对value进一步处理
.observeValues { (value) in
            print(value)
        }

innerObserver.send(value: 1)
innerObserver.sendCompleted()
输出: xxx1
  • on
public func on(
        event: ((Event) -> Void)? = nil,
        failed: ((Error) -> Void)? = nil,
        completed: (() -> Void)? = nil,
        interrupted: (() -> Void)? = nil,
        terminated: (() -> Void)? = nil,
        disposed: (() -> Void)? = nil,
        value: ((Value) -> Void)? = nil) -> Signal<Value, Error>
let (signal, innerObserver) = NSignal<Int>.pipe()

signal.on( value: { (value) in
    print("on value: \(value)")
}).observeValues { (value) in
    print("did received value: \(value)")
}

innerObserver.send(value: 1)
innerObserver.sendCompleted()
输出: on value: 1
      did received value: 1

在信号发送事件和订阅者收到事件之间插入一段事件处理逻辑, 你可以把它看做map的简洁版. (这个函数的参数很多, 但默认都有给nil, 所以你只需要关心自己需要的部分即可, 比如这里我只想在Value事件间插入逻辑)。

  • take(until:)
public func take(until trigger: Signal<(), NoError>) -> Signal<Value, Error>
let (signal, innerObserver) = NSignal<Int>.pipe()
let (takeSignal, takeObserver) = NSignal<()>.pipe()

signal.take(until: takeSignal).observeValues { (value) in
    print("received value: \(value)")
}

innerObserver.send(value: 1)
innerObserver.send(value: 2)

takeObserver.send(value: ())
innerObserver.send(value: 3)

takeObserver.sendCompleted()
innerObserver.sendCompleted()

输出: received value: 1
      received value: 2

在takeSignal发送Event之前, signal可以正常发送Event, 一旦takeSignal开始发送Event, signal就停止发送, takeSignal相当于一个停止标志位。

  • take(first:)

只取最初N次的Event. 类似的还有signal.take(last: ): 只取最后N次的Event。

public func take(first count: Int) -> Signal<Value, Error>
let (signal, innerObserver) = NSignal<Int>.pipe()
signal.take(first: 2).observeValues { (value) in
    print("received value: \(value)")
}

innerObserver.send(value: 1)
innerObserver.send(value: 2)
innerObserver.send(value: 3)
innerObserver.send(value: 4)

innerObserver.sendCompleted()
输出: received value: 1
      received value: 2
  • merge
    把多个信号合并为一个新的信号,任何一个信号有Event的时就会这个新信号就会Event发送出来。
public static func merge(_ signals: Signal<Value, Error>...) -> Signal<Value, Error>

let (signal1, innerObserver1) = NSignal<Int>.pipe()
let (signal2, innerObserver2) = NSignal<Int>.pipe()
let (signal3, innerObserver3) = NSignal<Int>.pipe()

Signal.merge(signal1, signal2, signal3).observeValues { (value) in
    print("received value: \(value)")
}

innerObserver1.send(value: 1)
innerObserver1.sendCompleted()

innerObserver2.send(value: 2)
innerObserver2.sendCompleted()

innerObserver3.send(value: 3)
innerObserver3.sendCompleted()
输出: received value: 1
     received value: 2
     received value: 3
  • combineLatest
    把多个信号组合为一个新信号,新信号的Event是各个信号的最新的Event的组合.
    "组合"意味着每个信号都至少有发送过一次Event, 并且组合的每个部分都要有值. 所以, 如果有某个信号一次都没有发送过Event, 那么这个新信号什么也不会发送, 不论其他信号发送了多少Event。
public static func combineLatest<S: Sequence>(_ signals: S) -> Signal<[Value], Error>
let (signal1, innerObserver1) = NSignal<Int>.pipe()
let (signal2, innerObserver2) = NSignal<Int>.pipe()
let (signal3, innerObserver3) = NSignal<Int>.pipe()

Signal.combineLatest(signal1, signal2, signal3).observeValues { (tuple) in
    print("received value: \(tuple)")
}

innerObserver1.send(value: 1)
innerObserver2.send(value: 2)
innerObserver3.send(value: 3)

innerObserver1.send(value: 11)
innerObserver2.send(value: 22)
innerObserver3.send(value: 33)

innerObserver1.sendCompleted()
innerObserver2.sendCompleted()
innerObserver3.sendCompleted()

输出: received value: (1, 2, 3)
      received value: (11, 2, 3)
      received value: (11, 22, 3)
      received value: (11, 22, 33)
  • zip
    新信号的Event是各个信号的最新的Event的进行拉链式组合,只有各个信号发送Event的次数相同(对齐)时, 新信号才会发送组合值. 同理, 如果有信号未发送那么什么也不会发生。
public static func zip<S: Sequence>(_ signals: S) -> Signal<[Value], Error>
let (signal1, innerObserver1) = NSignal<Int>.pipe()
let (signal2, innerObserver2) = NSignal<Int>.pipe()
let (signal3, innerObserver3) = NSignal<Int>.pipe()

Signal.zip(signal1, signal2, signal3).observeValues { (tuple) in
        print("received value: \(tuple)")
}

innerObserver1.send(value: 1)
innerObserver2.send(value: 2)
innerObserver3.send(value: 3)

innerObserver1.send(value: 11)
innerObserver2.send(value: 22)
innerObserver3.send(value: 33)

innerObserver1.send(value: 111)
innerObserver2.send(value: 222)

innerObserver1.sendCompleted()
innerObserver2.sendCompleted()
innerObserver3.sendCompleted()

输出: received value: (1, 2, 3)
      received value: (11, 22, 33)

相关文章

网友评论

      本文标题:ReactiveSwift框架分析6 — 操作符

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