前言
通过前面几篇文章了解了很多RxSwift
中的概念和序列操作。下面从一个最基础的例子来看看实际开发中的被观察者和订阅者。
这里要实现的仅仅是输入三个整数并实时把三个整数相加的结果显示出来。
界面设计
这里没有界面设计就是拖了几个UITextField
。
当每次上面的三个输入框输入改变了的话,就把三个值相加显示出来。
项目准备
首先创建一个Swift
的项目RxSwiftCalculator
,Podfile
内容如下:
1 | use_frameworks! |
因为需要用到UI控件里面的Rx扩展,所有引入了RxCocoa
。
pod install
后打开RxSwiftCalculator.xcworkspace
。
把界面拖一下, 然后关联到属性。
UITextField.rx.text
在这个项目里面我们要监听UITextField
的事件,然后把里面的数字取出来相加,最后显示到result
这个Label
上面。
所以本例中UITextField
就是一个被观察者。
在RxCocoa
里面已经对UITextField
进行了扩展,把的里面的文本变成一个可被观察的对象text
,源码:
1 | extension Reactive where Base: UITextField { |
这里返回的是一个ControlProperty
类型的字符串,而ControlProperty
实现了协议ControlPropertyType
。
1 | public struct ControlProperty<PropertyType> : ControlPropertyType { |
跟进ControlPropertyType
:
1 | /// Protocol that enables extension of `ControlProperty`. |
可以看到ControlPropertyType
实现了两个协议ObservableType
和ObserverType
。所以它即可是一个可被观察的对象,同时也可以作为观察者。
同时,我们看到这里返回了一个UIControl.rx.value
生成的对象,跟进去看一下:
1 | static func value<C: UIControl, T>(_ control: C, getter: @escaping (C) -> T, setter: @escaping (C, T) -> Void) -> ControlProperty<T> { |
这里创建了一个可被观察者,那么发射的值是什么时候发射的呢? 跟进ControlTarget
的init
方法:
1 | init(control: Control, controlEvents: UIControlEvents, callback: @escaping Callback) { |
这里的control
就传进来的UITextField
对象,然后把它的controlEvents
事件绑定到了selector
,这个selector
是:
1 | let selector: Selector = #selector(ControlTarget.eventHandler(_:)) |
然后这个方法里面会调用初始化传进来的callback
:
1 | func eventHandler(_ sender: Control!) { |
然后callback
里面调用:
1 | observer.on(.next(getter(control))) |
发射一个值,调用getter
:
1 | getter: { textField in |
也就是发射了一个textField.text
。
这个时候应该明白是怎么回事了吧。
监听UITextField
这里测试一下监听UITextField
的事件触发发射出来的text
。
1 | numberOne.rx.text.asObservable().subscribe{ |
把它变成一个可被观察者,然后订阅它。
程序启动会发射一个Optional("")
, 获得焦点或也会发射一个Optional("")
,然后每次输入都会把当前的文本发射出来:
1 | next(Optional("")) |
这里发现它是一个Optional
的值,可以通过orEmpty
可以把String?
转成String
。
1 | numberOne.rx.text.orEmpty.asObservable().subscribe{ |
我们再想把空字符串过滤掉,可以使用filter
,就不会订阅到next()
了。
1 | numberOne.rx.text.orEmpty.asObservable() |
combineLatest
还记得我们的目的是获取最新的text
然后相加再显示到result
吧,那么这里我们可以使用combineLatest
来获取最新序列的组合。
1 | Observable.combineLatest(numberOne.rx.text.orEmpty,numberTwo.rx.text.orEmpty,numberThree.rx.text.orEmpty) { (numberOneText, numberTwoText, numberThreeText) -> Int in |
首先获取最新输入的字符串,然后转成Int
, 因为字母会转换失败,所以返回的是一个Optional
,如果转换失败就默认0,然后相加返回,再转成字符串绑定到result.rx.text
。
这里的bindTo
其实就是订阅序列,然后更新result.rx.text
的值。
总结
虽然这个例子比较简单,但是相信大家能够体会到前面的一大堆概念在开发的应用以及带给我们的便利了,后续会继续学习复杂一点的例子。
本文代码地址: