美文网首页
RxSwift官方实例三(API包装)

RxSwift官方实例三(API包装)

作者: 酒茶白开水 | 来源:发表于2020-08-09 12:50 被阅读0次

代码下载

搭建UI

搭建下图UI:


UI

UI控件处理

简单控件处理

首先定义一个用于显示信息的函数:

    func debug(_ param: String) {
        print(param)
        label.text = param
    }

UITapGestureRecognizer处理:

        pan.rx.event.subscribe(onNext: {
            if self.textField.isFirstResponder || self.textField1.isFirstResponder || self.textView.isFirstResponder || self.textView1.isFirstResponder {
                self.view.endEditing(true)
            } else {
                self.debug("UIGestureRecognizer event \($0.state.rawValue)")
            }
        }).disposed(by: bag)

UIBarButtonItem处理:

        item.rx.tap.bind {
            self.debug("UIBarButtonItem Tapped")
        }.disposed(by: bag)

UISlider处理:

        slider.rx.value.subscribe(onNext: {
            self.debug("UISlider value \($0)")
        }).disposed(by: bag)

UIButton处理:

        button.rx.tap.subscribe(onNext: {
            self.debug("UIButton Tapped")
        }).disposed(by: bag)

UIDatePicker处理:

        datePicker.rx.date.subscribe(onNext: {
            self.debug("UIDatePicker date \($0)")
        }).disposed(by: bag)

双向绑定

双向绑定是通过BehaviorRelay来实现的,定义如下<->操作符方便UI控件的ControlProperty序列的双向绑定:

func <-><T>(property: ControlProperty<T>, relay: BehaviorRelay<T>) -> Disposable {
#if DEBUG
    if T.self == String.self {
        fatalError("删除这个信息也是可以的,但是这是在提醒开发者有可能试着将一些“rx.text”属性绑定到relay。\n" +
            "这通常能够很好的工作,但是对于一些IME语言这种简单的方法将造成意外的问题,因为当文本正在输入时将会返回中间结果。\n" +
            "解决方案: 就是使用 `textField <-> relay` 替换 `textField.rx.text <-> relay`.\n" +
        "了解更多: https://github.com/ReactiveX/RxSwift/issues/649\n")
    }
#endif
    
    let bind = relay.bind(to: property)
    let bindRelay = property.subscribe(onNext: { (n) in
        relay.accept(n)
    }, onCompleted: {
        bind.dispose()
    })
    
    return Disposables.create(bind, bindRelay)
}

代码分析:

  1. 将BehaviorRelay序列的值绑定到ControlProperty序列上
  2. 订阅ControlProperty序列的值
  3. ControlProperty序列发出元素时BehaviorRelay序列也通过accept操作符发出元素,完成时通过dispose操作符清理BehaviorRelay序列
  4. 返回订阅ControlProperty序列的Disposable

注意:
在这里有一个问题就是当对字符串文本进行双向绑定时,因为当文本正在输入时将会返回中间结果,对于一些IME语言这种简单的方法将造成意外的问题。解决方案就是使用 textField <-> relay 替换 textField.rx.text <-> relay

具体代码代码实现:

func <-><Base>(textInput: TextInput<Base>, relay: BehaviorRelay<String>) -> Disposable {
    let bind = relay.bind(to: textInput.text)
    let bindRelay = textInput.text.subscribe(onNext: { (n) in
        if let nonMarkedText = nonMarkedText(textInput.base), nonMarkedText != relay.value {
            relay.accept(nonMarkedText)
        }
    }, onCompleted: {
        bind.dispose()
    })
    
    return Disposables.create(bind, bindRelay)
}

UISegmentedControl处理:

        let value = BehaviorRelay(value: 0)
        _ = segmentedControl.rx.value <-> value
        value.asObservable().subscribe(onNext: { (v) in
            self.debug("UISegmentedControl value \(v)")
        }).disposed(by: bag)

UISwitch处理:

        let switchV = BehaviorRelay(value: true)
        _ = switcher.rx.value <-> switchV
        switchV.asObservable().subscribe(onNext: {
            self.debug("UISwitch value \($0)")
        }).disposed(by: bag)
        switcher.rx.value.bind(to: activityIndicator.rx.isAnimating).disposed(by: bag)

UITextField处理:

        // MARK: UITextField

        // 在ios 11.2中存在内存泄漏
        //
        // 最终的类UITextFieldSubclass: UITextField { deinit { print("不会调用")  } }
        if #available(iOS 11.2, *) {
            let textV = BehaviorRelay(value: "")
            _ = textField.rx.textInput <-> textV
            textV.asObservable().subscribe(onNext: {
                self.debug("UITextField text \($0)")
            }).disposed(by: bag)
            
            let textV1 = BehaviorRelay<NSAttributedString?>(value: NSAttributedString(string: ""))
            _ = textField1.rx.attributedText <-> textV1
            textV1.asObservable().subscribe(onNext: {
                self.debug("UITextField attributedText \($0?.description ?? "")")
            }).disposed(by: bag)
        }

注意:在ios 11.2中存在内存泄漏,继承自UITextField最终的类不会执行deinit函数。

UITextView处理:

        let textViewV = BehaviorRelay(value: "")
        _ = textView.rx.textInput <-> textViewV
        textViewV.asObservable().subscribe(onNext: {
            self.debug("UITextView text \($0)")
        }).disposed(by: bag)
        
        let textViewV1 = BehaviorRelay<NSAttributedString?>(value: NSAttributedString(string: ""))
        _ = textView1.rx.attributedText <-> textViewV1
        textViewV1.asObservable().subscribe(onNext: {
            self.debug("UITextView attributedText \($0?.description ?? "")")
        }).disposed(by: bag)

相关文章

网友评论

      本文标题:RxSwift官方实例三(API包装)

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