RxSwift使用教程
前言RxSwift是Swift函数响应式编程的一个开源库,由Github的ReactiveX组织开发,维护。 RxSwift的目的是让让数据/事件流和异步任务能够更方便的序列化处理,能够使用Swift进行响应式编程 目前,RxSwift在Github上收到了5000+Star,600+fork。 本文的目的
如果你有时间,建议先读读RxSwift的文档,这会给你一个最基本的认识 本文不会讲解函数式编程,也不会讲解函数响应式编程的概念,计划后面单独出一篇博客来讲解Swift与函数式编程。 本文来自于官方文档的翻译,官方example代码的阅读,以及自己的理解 RxSwift和ReativeCocoa老一点的iOS开发者应该对ReativeCocoa有一些了解,iOS响应式编程的鼻祖。就个人来看
So,个人是非常推荐RxSwift的 Observables/Sequences先复习下SequenceType。这是Swift中的一个协议,比如Swift中的Array就遵循这个协议,通过这个协议,你可以这样的去操作一个Array let array = [1,2,3,4,5]
let array2 = array.filter({$0 > 1}).map({$0 * 2})//4 6 8 10
var indexGenerator = array2.generate()
let fisrt = indexGenerator.next() // 4
let SEOncd = indexGenerator.next() //6
也就是说,把Array作为一个序列,然后依次对这个序列进行过滤,映射等操作,也可以通过indexGenerator来一个个的获取序列中的数据。 RxSwift的核心思想和这个类似。 RxSwift的核心是想是
本文把RxSwift中的序列的每一个Element成为信号,因为异步的Element是与时间相关的,称作信号更好理解一点 RxSwift中, enum Event<Element> {
case Next(Element) // 新的信号到来
case Error(ErrorType) // 信号发生错误,序列不会再产生信号
case Completed // 序列发送信号完成,不会再产生新的信号
}
protocol ObserverType {
func on(event: Event<Element>) //监听所有的信号
}
取消监听Observable分为两种
class Observable<Element> {
func subscribe(observer: Observer<Element>) -> Disposable //调用Disposable的方法来取消
}
当然,除了手动释放,RxSwift提供了一些操作符,比如 sequence
.takeUntil(self.rx_deallocated) //当对象要释放的时候,取消监听
.subscribe {
print($0)
}
信号处理的顺序Observable有个隐式的约定,那就是在一个信号处理完成之前,不会发送下一个信号,不管发送信号的线程是并发的or串行的。 比如 someObservable
.subscribe { (e: Event<Element>) in print("Event processing started") // processing print("Event processing ended") }
只会出现 Event processing started
Event processing ended
Event processing started
Event processing ended
Event processing started
Event processing ended
不会出现 Event processing started
Event processing started
Event processing ended
Event processing ended
第一个例子我们监听textfield的文字变化,然后,Log出text,当button点击的时候,取消这次监听 class ObservableAndCancelController : UIViewController{ var subscription:Disposable? @IBOutlet weak var textfield: UITextField! @IBAction func cancelObserve(sender: AnyObject) { subscription?.dispose() } override func viewDidLoad() { super.viewDidLoad() subscription = textfield.rx_text.subscribeNext { (text) in print(text) } } }
RxSwift用extensiton的方式,为UITextfield,UIlabel等控件添加了很多可监听的属性,这里的textfield.rx_text就是一个 效果:随着文字输入,实时Log出textfield的文字,当点击button之后,再输入,则不会Log 操作符(Operators)在上文的第一个例子里面,你看到了监听信号,并且log出值。事实上,这样直接处理信号的时候是很少的,很多时候,我们需要对信号进行映射,过滤,这时候我们就要用到操作符了。在这个文档里,你可以找到所有的操作符。 关于操作符效果,你可以参见http://rxmarbles.com/的可视化效果,这会给你一个更好的理解 例子二,map,filter,combineLatest
例如 let firstObserverable = firstTextfield.rx_text.map({"first" + $0})
let secondObserverable = secondTextfield.rx_text.filter({$0.characters.count > 3})
_ = Observable.combineLatest(firstObserverable,secondObserverable,resultSelector:{ ($0 + $1,$0.characters.count + $1.characters.count)}).subscribeNext { (element) in
print("combineLatest:(element)")
}
对于,每一个fistTextfield的信号,在字符串开始处增加”first”;对secondTextfield的信号进行过滤,当长度大于3的时候,才会继续传递。对两个信号进行结合,取truple类型,然后打印出来。 所以,当我在fistTextfield中,输入1234,然后secondTextfield中依次输入abcdefg的时候 combineLatest:("first1234abcd",13)
combineLatest:("first1234abcd3",14)
combineLatest:("first1234abcd",13)
combineLatest:("first1234abcde",14)
combineLatest:("first1234abcdef",15)
combineLatest:("first1234abcdefg",16)
例子三,创建一个Observable Observerable可以用来处理任务,并且异步返回Event信号(Next,Error,Completion) 比如,这样一个方法 //Observable就是处理输入,并且把description发送出去
func createObserveable(object:AnyObject?)->Observable<String?>{
return Observable.create({ observer in
observer.onNext(object?.description)
observer.onCompleted()
return NopDisposable.instance
})
}
这样调用 _ = createObserveable(test).subscribe({ (event) in
switch event{
case .Next(let value):
print(value)
case .Completed:
print("Completed")
case .Error(let error):
print(error)
}
})
然后,Log如下 Optional("{n a = b;n 1 = 2;n}")
Completed
可以看到,创建一个Observable相当容易,调用Observable.create,在必要的时候发送onNext,onError,onCompleted信号。然后返回一个Disposable用来取消信号 throttle/retry/distinctUntilChanged/flatMapLatest
最直接的例子就是搜索,通常我们想要
这时候,用RxSwift你得代码会变的非常简单 let searchResults = searchBar.rx_text
.throttle(0.3,scheduler: MainScheduler.instance)
.distinctUntilChanged()
.flatMapLatest { query -> Observable<[Repository]> in
if query.isEmpty {
return Observable.just([])
}
return doSearchAPI(query).retry(3)
.catchErrorJustReturn([])
}
.observeOn(MainScheduler.instance)
这里简单讲解下作用
SchedulersSchedulers 抽象化了线程,线程池,GCD中操作队列,Runloop等概念。可以理解为,Schedulers就是一个执行任务的线程。 有一点要注意:默认一个Observerable在其创建的线程上执行 与Schedulers相关的操作符有两个
比如 sequence1
.observeOn(backgroundScheduler)
.map { n in
print("This is performed on the background scheduler")
}
.observeOn(MainScheduler.instance)
.map { n in
print("This is performed on the main scheduler")
}.subscribeOn(backgroundScheduler)
.subscribeNext{ n in
print("This is performed on the background scheduler")
}
默认一个subscribeNext或者subscribe在其调用的线程上执行 Serial/Concurrent Schedulers 串行或并行和GCD的队列很相似,并行Schedulers的任务可以并发之行,串行Schedulers只能依次之行。不过RxSwift有内部机制,保证上文提到的信号处理的顺序 RxSwift内置的Scheduler通常,使用内置的Scheduler足矣。
例子四,在后台Scheduler之行任务,然后在主线程上更新UI VariableVariable表示一个可监听的数据结构。使用Variable,你可以监听数据的变化,也可以把其他值绑定到它身上。 当Variable被释放的时候,它会向监听者发送onCompleted 例子五,Variable进行监听 class VariableController: UIViewController { @IBOutlet weak var label: UILabel! var timer:NSTimer? var count = Variable(0) override func viewDidLoad() { super.viewDidLoad() timer = NSTimer.scheduledTimerWithTimeInterval(1.0,target: self,selector:#selector(VariableController.updateValue),userInfo: nil,repeats: true) _ = count.asObservable().subscribeNext { (num) in self.label?.text = "VariableValue:(num)" } } func updateValue(){ count.value = count.value + 1 } override func viewDidDisappear(animated: Bool) { super.viewDidDisappear(animated) timer?.invalidate() } }
数据绑定数据绑定是开发的时候很常见的,比如根据文本的输入动态调整textfield的背景色,动态调整按钮的enable。亦或者根据textfield的输入变化,动态的去反馈到model层。如果你听过MVVM,那你肯定知道,MVVM的难点就是ViewModel与View的数据绑定问题。 不过,使用RxSwift,数据绑定变的十分容易,你甚至可以把数据绑定到tableview和collectionView上去。 例子六,bindTo _ = mySwitch.rx_value.bindTo(testView.rx_hidden)
例子七,根据输入,进行View状态绑定 我们想要实现这样的状态
信号的处理方式如下, let nameObserable = nameTextfield.rx_text.shareReplay(1).map({$0.characters.count >= 6})
let pwdObserable = passwordTextfield.rx_text.shareReplay(1).map({$0.characters.count >= 8})
_ = nameObserable.subscribeNext({ (valid) in
self.nameTextfield.backgroundColor = valid ? UIColor.clearColor():UIColor.lightGrayColor()
}).addDisposableTo(disposeBag)
_ = pwdObserable.subscribeNext({ (valid) in
self.passwordTextfield.backgroundColor = valid ? UIColor.clearColor(): UIColor.lightGrayColor()
}).addDisposableTo(disposeBag)//addDisposableTo(disposeBag)是为了自动释放
_ = Observable.combineLatest(nameObserable,pwdObserable) {$0 && $1}.subscribeNext({valid in
if valid{
self.registerButton.enabled = true
self.registerButton.backgroundColor = UIColor.redColor()
}else{
self.registerButton.enabled = false
self.registerButton.backgroundColor = UIColor.darkGrayColor()
}
}).addDisposableTo(disposeBag)
_ = registerButton.rx_tap.shareReplay(1).subscribeNext {
print("Button tapped")
}
共享监听Sharing subscription-
|