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

ReactiveSwift框架分析6 — 操作符

作者: 沈枫_SerenF | 来源:发表于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