美文网首页
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