最近接触了RxSwift,有一些心得自己学习体会,有不对的地方还望各路大神多多指教,不喜勿喷,没有官方文档那么正式,根据自己的理解来的
RxSwift
RxSwift的目的是让让数据/事件流和异步任务能够更方便的序列化处理,能够使用swift进行响应式编程[^footnote]
-* ObserVerable*
-* CombineLatest*
-* bindTo*
ObserVerable
Observable也就是一个被观察的对象,是一个事件序列,订阅者可以订阅它,监测事件的发生(Next\Complete\Error)。是不是听到这里就感觉这货有点像KVO?
获得Observable
要得到一个Observable有两种方式,一种是RxSwift已经提供了的(这里你可能需要引入RxCocoa),一种是自己创建。比如你有一个UITextfield,你要订阅其text的变化,就可以通过textfield.rx_text来获得这个Observable的对象。如果要自己创建的话,可以利用它提供的create函数来创建,create接受函数闭包作为参数
这是一个对数组的拓展每次遍历,由AnyObserver发出一个event,而调用者会收到这个event来进行调用
extension Array {
///遍历数组
var rx_traversal:Observable<AnyObject> {
return Observable.create({ (obs) -> Disposable in
for item in self {
obs.on(Event.next(item as AnyObject))///发出信号
}
obs.onCompleted()
return Disposables.create {
debugPrint("遍历完毕")
}
})
}
}
调用如下
let disbg = DisposeBag()//我的理解是这个信号源的声明周期,当DisposeBag这个对象被释放那么该监听就不在生效
["1","2","3","4"].rx_traversal.subscribe { (event) in
if let element = event.element {
debugPrint(element)//接受信号
}
}.addDisposableTo(disbg)
combineLatest
简单使用
理解的就是将信号源合并成一个信号源然后去做某一件事情,上面我用一个类似仿登录的手机号11位验证码6位的一个事件处理方法:
如果是常规处理那么:
手机号输入
(phoneInput.rx.text).subscribe { (event) in ///手机号满足的处理 refreshcanup() }.addDisposableTo(disbg)
验证码输入
(passInput.rx.text).subscribe { (event) in ///验证码或密码满足的处理 refreshcanup() }.addDisposableTo(disbg)
两者都满足的情况
fun refreshcanup()///刷新提示框的属性
但是如果用combineLatest方式处理的话:
ps:先普及一下sharereplay(转的)
///passwordOutlet.rx_enabled。第一个观察者订阅usernameValid时,调用map里的print函数,第二个观察者在订阅时(没有添加.shareReplay(1))时,又再次调用map里的print函数,以此类推,如果有很多观察者的话就要调用很多次,而从第二个观察者开始需要的只是map返回的一个序列,而不是让其徒劳地调用map里的函数,那么怎样解决在多个观察者订阅时多次重复调用执行的问题?
使用shareReplay(bufferSize: Int)就ok了。
//shareReplay会返回一个新的事件序列,它监听底层序列(这里指的是map返回的序列)的事件,并且通知自己的订阅者们。不过和传统的订阅不同的是,它是通过『重播』的方式通知自己的订阅者,因此在这里通过shareReplay订阅的map并不会调用多次。
// 参数bufferSize指的是重播的最大元素个数,因为usernameValid是一个只有一个元素的序列observable,因此shareReplay参数为1;假如对于一个有5个元素的序列,你只需要重复播报最后3个,那么就写成.shareReplay(3),就酱紫。
let phoneobser = (phoneInput.rx.text).shareReplay(1).map{
$0?.characters.count == 11
}
let passobserver = (passInput.rx.text).shareReplay(1).map{
$0!.characters.count >= 6
}
_ = Observable.combineLatest(phoneobser, passobserver, resultSelector: {
($0 && $1)
}).subscribe({[weak self] (event) in
if let b = event.element {
self?.canclik.backgroundColor = b ? UIColor.blue:UIColor.gray
}
})
还有更简单的方法上述是通过合并两个信号源来提供合并属性请继续往下看
binTO
简单使用
我的理解就是将已经信号源去用一个UIBindingObserver去接受,当接收到的属性是true进行相应的操作
为登录按钮写一个rx_click的拓展
///首先写一个UIBindingObserver
var rx_click:AnyObserver<Bool> {
return UIBindingObserver.init(UIElement: self, binding: { (lab, result) in
lab.backgroundColor = result ? UIColor.blue:UIColor.gray
}).asObserver()
}
//*binto 信号合并处理 binto发送信号
//
// combineLatest(合并信号) bind
// observer ----------------------->处理信号时间------------->处理信号
//
//
///然后手机号11位 验证码 6位就可以用这一行代码解决
let _ = Observable.combineLatest(phoneobser, passobserver, resultSelector: {
$0 && $1
}).bind(to: canclik.rx_click)
用RxSwift和Alamofire去请求数据
使用一个RxNetUtils去写一个类方法参数是url跟params还有原始json回调
T 是一个泛型
class RxNetUtils<T:BaseBean>:NSObject {
typealias dataSrc = T
///请求list数据
/// - parameter url:网址
/// - parameter params:参数
/// - parameter getJSONdata:拿到原始json数据可以为空
class func request(url:String,params:[String:String],getJSONdata:((JSON)->Void)?) -> Observable<dataSrc> {
return Observable.create({ (obserable) -> Disposable in
HUDUtil.showHud()//出现hud动画
RequestClient<dataSrc>.request(method: .post, url: url, params: params, jsonDatacallback: { (json) in
///拿到原始json数据成功
getJSONdata?(json)
}, successful: { (data) in
HUDUtil.hideHud()//隐藏hud动画
///请求数据网络成功 发送两次事件一次event 一次向下从传递
obserable.onNext(data)
obserable.on(Event.next(data))
// obserable.onCompleted()
}, failed: { (error) in
///抛出错误信息
obserable.onError(error)
HUDUtil.showHudWithText(text: error.localizedDescription, delay: 1.0)
})
return Disposables.create {
//TODO: 取消请求
debugPrint("\(url)结束本次请求")
}
})
}
}