RxSwift-双向绑定

简介: RxSwift-双向绑定

在我们的实际开发中,在MVVM模式下,多数场景是,我们把ViewModel绑定到UI控件上,当ViewModel发生变化时,控件也跟着改变,而有些时候我们要同时实现当我们改变控件值时,ViewModel也跟着变化,这个时候就需要双向绑定,接下来我们就逐步实现一下双向绑定;

说明:双向绑定的ViewModel的属性值一定是基于既是Observable又是Observer


需求描述:有一个文本输入框和一个ViewModel,当文本内容变化的时候,ViewModel里面的值跟随着改变,当ViewModel的值变化的时候,输入框的内容也跟着改变;

首先看ViewModel里面的内容:

struct ViewModel {
    let phoneNumber = BehaviorRelay<String?>(value: nil)
}


phoneNumber变化的时候textFieldtext文本跟着变化:


viewModel.phoneNumber.asObservable().bind(to: textField.rx.text).disposed(by: disposeBag)


textFieldtext文本变化的时候phoneNumber跟着变化:


textField.rx.text.asObservable().bind(to: viewModel.phoneNumber).disposed(by: disposeBag)


最后监听当phoneNumber变化的时候labeltext文本跟着变化,目的仅为了在UI层展示:


viewModel.phoneNumber.asObservable().bind(to: label.rx.text).disposed(by: disposeBag)


上述几步我们通过效果可以看到已经可以实现当任意一个变化的时候都会通知到对方,那么我们可否来封装一下上述操作呢?接下来我们采用自定义操作符的方式来把上述操作封装一下:

首先定义一个运算符:


infix operator <---> : DefaultPrecedence

<--->函数参数一个是用于描述基于UI控件的ControlProperty,另一个是既是Observable又是ObserverBehaviorRelay,最后给定一个返回值,类型为Disposables(此处返回值可有可无、仅为了演示)

func <--->(property: ControlProperty<String?>, relay: BehaviorRelay<String?>) -> Disposable {
    let disposable = relay.bind(to: property)
    let disposable2 = property.asObservable().bind(to: relay)
    return Disposables.create(disposable, disposable2)
}


最后来调用一下,并把结果绑定到label

let _ = textField.rx.text <---> viewModel.phoneNumber
viewModel.phoneNumber.asObservable().bind(to: label.rx.text).disposed(by: disposeBag)


通过运行效果我们可以看到也是满足了我们的需求的;实际RxSwift自带的Demo里面也封装好了用于双向绑定的运算符,可以参考GitHub中对应的Operators.swift文件,接下来我们看一下它的实现:

func <-> <T>(property: ControlProperty<T>, relay: BehaviorRelay<T>) -> Disposable {
    if T.self == String.self {
#if DEBUG && !os(macOS)
        fatalError("It is ok to delete this message, but this is here to warn that you are maybe trying to bind to some `rx.text` property directly to relay.\n" +
            "That will usually work ok, but for some languages that use IME, that simplistic method could cause unexpected issues because it will return intermediate results while text is being inputed.\n" +
            "REMEDY: Just use `textField <-> relay` instead of `textField.rx.text <-> relay`.\n" +
            "Find out more here: https://github.com/ReactiveX/RxSwift/issues/649\n"
            )
#endif
    }
    let bindToUIDisposable = relay.bind(to: property)
    let bindToRelay = property
        .subscribe(onNext: { n in
            relay.accept(n)
        }, onCompleted:  {
            bindToUIDisposable.dispose()
        })
    return Disposables.create(bindToUIDisposable, bindToRelay)
}

可以看到它封装的方法,实现双向绑定的原理都是一致的,内部限制了ControlPropertyBehaviorRelay的参数必须是String类型,否则会抛出异常;绑定的时候通过relay绑定到了property上,当relay改变的时候,property会跟着改变;property通过订阅的形式,当property监听到改变的时候,relay发出信号值也跟着改变;


复制搜一搜分享收藏划线


相关文章
|
6月前
|
前端开发 JavaScript
第九章 React中的事件处理
第九章 React中的事件处理
|
前端开发 测试技术 数据安全/隐私保护
使用 React-Hook-Form 让你的表单天生强大
使用 React-Hook-Form 让你的表单天生强大
1751 0
|
22天前
|
监控 前端开发 UED
理解 MVVM 中的数据双向绑定
【10月更文挑战第21天】数据双向绑定是 MVVM 架构中的一个核心特性,它为前端开发带来了诸多便利和优势。理解并熟练运用数据双向绑定,有助于我们构建更加高效、交互性更强的应用程序。同时,我们也需要在实际应用中注意性能和复杂性等方面的问题,以确保应用的良好运行和用户体验。还可以结合具体的项目经验和实际案例,进一步深入探讨数据双向绑定在不同场景下的应用和优化策略。
|
2月前
|
JSON 前端开发 JavaScript
双向绑定
双向绑定
16 1
在实现自定义组件双向绑定时,有哪些需要注意的地方
在实现自定义组件双向绑定时,有哪些需要注意的地方
|
API Swift iOS开发
【Vue3 第十五章】组件中的双向绑定
【Vue3 第十五章】组件中的双向绑定
113 0
|
前端开发
react关于受控组件的数据双向绑定
react关于受控组件的数据双向绑定
108 0
|
JavaScript 前端开发 容器
学习Vue3 第十九章(Teleport传送组件)
Teleport 是一种能够将我们的模板渲染至指定DOM节点,不受父级style、v-show等属性影响,但data、prop数据依旧能够共用的技术;类似于 React 的 Portal。
131 0
学习Vue3 第十九章(Teleport传送组件)
|
JavaScript 前端开发
Vue.js事件修饰符及v-model双向数据绑定
Vue.js事件修饰符及v-model双向数据绑定
162 0