根据自己对RxSwift的理解写了一个登陆以及验证码倒计时
Observer
一个可以被观察的对象被观察者监听
Observerable
观察者 产生信号推送给订阅者
/// A type-erased `ObservableType`.
///
/// It represents a push style sequence.
public class Observable<Element> : ObservableType {
登陆业务的整体处理逻辑为
整个业务处理流程为 创建 (账号密码输入框文字改变)的观察者 ---》 发送响应信号 ---》 筛选并合并响应信号 ===》 订阅收到相应信号并处理
首先创建账号文字改变和密码文字改变的观察者 然后通过这个序列得到一个新的账号密码是否符合规范的序列输入框改变后通知accontobseque响应 最后将两个序列信号合并条件符合后再通知loginobserver(Observer)进行响应的ui处理
///
let inputaccontObserVerable = accontTextField.rx.text
let inputpasswordObserVerable = passwordTextField.rx.text
/**
Returns an observable sequence that **shares a single subscription to the underlying sequence**, and immediately upon subscription replays elements in buffer.
This operator is equivalent to:
* `.whileConnected`
```
// Each connection will have it's own subject instance to store replay events.
// Connections will be isolated from each another.
source.multicast(makeSubject: { Replay.create(bufferSize: replay) }).refCount()
```
* `.forever`
```
// One subject will store replay events for all connections to source.
// Connections won't be isolated from each another.
source.multicast(Replay.create(bufferSize: replay)).refCount()
```
It uses optimized versions of the operators for most common operations.
- parameter replay: Maximum element count of the replay buffer.
- parameter scope: Lifetime scope of sharing subject. For more information see `SubjectLifetimeScope` enum.
- seealso: [shareReplay operator on reactivex.io](http://reactivex.io/documentation/operators/replay.html)
- returns: An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
*/
// shareReplay 会返回一个新的事件序列,它监听底层序列的事件,并且通知自己的订阅者们。
// 解决有多个订阅者的情况下,map会被执行多次的问题。
// 返回一个可观察序列,该序列**共享对基础序列**的单个订阅,并在订阅后立即在缓冲区中重播元素。
//参数replay:重放缓冲区的最大元素计数。
// public func share(replay: Int = default, scope: RxSwift.SubjectLifetimeScope = default) -> RxSwift.Observable<Self.E>
let accontobseque = inputaccontObserVerable.share(replay: 1).map {
return $0!.count == 11
}
/// 返回一个可观察的序列 比如 输入的信号为 1,12,123 那么将这个信号转换为 false,false,false,具体可以根据业务需求来
let passwordseque = inputpasswordObserVerable.share(replay: 1).map {
return $0!.count == 6
}
//返回username和password组合后的流
let _ = Observable.combineLatest(accont.asObservable(), password.asObservable()) {
return ($0, $1)
}.bind(to: loginobserver)
extension LoginViewController {
/// 被观察者 loginobserver
private var loginobserver: AnyObserver<Bool> {
return AnyObserver.init(eventHandler: { [weak self] (event) in
if let canlogin = event.element {
self?.loginBtn.backgroundColor = canlogin ? UIColor.red:UIColor.gray
}
}).asObserver()
}
ui逻辑整理好后处理业务逻辑新建一个LoginViewmodel
初始化方法为
convenience init(vc: LoginViewController) {
self.init()
self.ctr = vc
setUpBindSignal()
}
实现业务与界面的双向绑定
var accont: Driver<String?>!
var password: Driver<String?>!
var msmcode: Driver<String>!
let msmhaviorsubject = BehaviorSubject<String>.init(value: "")
private func setUpBindSignal() {
accont = (ctr.accontTextField.rx.text).asDriver()
password = (ctr.passwordTextField.rx.text).asDriver()
let _ = msmhaviorsubject.asDriver(onErrorJustReturn: "").drive(ctr.msmlab.rx.text)
}
当点击登录方法后合并账号和密码信息通过flatmaplatest返回一个观察者对象等到完成后通知绑定的业务逻辑进行登录处理
//返回username和password组合后的流
let _ = Observable.combineLatest(accont.asObservable(), password.asObservable()) {
return ($0, $1)
}.flatMapLatest { (arg0) -> Observable<Loginmodel> in
let (user, pass) = arg0
debugPrint("用户名:\(user!) 密码:\(pass!)")
return self.client.login(accont: user!, password: pass!)
}.bind(to: ctr.finishbserver)
extension LoginViewController {
var finishbserver: AnyObserver<Loginmodel> {
return AnyObserver.init(eventHandler: { [weak self] (event) in
if let loginmodel = event.element {
self?.loginstatusLab.text = loginmodel.username
}
}).asObserver()
}
}
网络请求层处理到此一个完整的登录和结果展示就成功了还有一个短信验证码倒计时实现了与界面的绑定。
class NetClient: NSObject {
func login(accont: String,password: String) -> Observable<Loginmodel> {
return Observable<Loginmodel>.create({ (event) -> Disposable in
sleep(2)
let loginmodel = Loginmodel()
loginmodel.status = "登录成功"
loginmodel.username = "红鲤鱼与绿鲤鱼与驴"
/// 直接向订阅者发送信号
event.on(Event.next(loginmodel))
event.on(Event.completed)
//event.onNext(<#T##element: Loginmodel##Loginmodel#>)
//event.onError(<#T##error: Error##Error#>)
//event.onCompleted()
/// 订阅next信号 和 err信号 还有完成信号 并进行不同的处理
///订阅方法为 subsrcir(onnext...,onerror:....,oncomplete:...,ondisponse:.... )
///subscribe(onNext: <#T##((Loginmodel) -> Void)?##((Loginmodel) -> Void)?##(Loginmodel) -> Void#>, onError: <#T##((Error) -> Void)?##((Error) -> Void)?##(Error) -> Void#>, onCompleted: <#T##(() -> Void)?##(() -> Void)?##() -> Void#>, onDisposed: <#T##(() -> Void)?##(() -> Void)?##() -> Void#>)
return Disposables.create {
}
})
}
}
map
这个方法跟数组自带的api一样map遍历一个数组通过transform处理这个数组并得到一个期望返回值的数组例如
var arr = [1,2,3,4]
let newer = arr.map<Bool>.map {
/// 处理
}
那么newarr就是一个bool类型的数组
同理 遍历这个
public func map<R>(_ transform: @escaping (Self.E) throws -> R) -> RxSwift.Observable<R>
flatmap
flatMap, flatMapLatest 让观察者观察的东西变成动态的了. 后者是只观察最后一个值.
let _ = Observable.combineLatest(accont.asObservable(), password.asObservable()) {
return ($0, $1)
}.flatMapLatest { (arg0) -> Observable<Loginmodel> in
let (user, pass) = arg0
debugPrint("用户名:\(user!) 密码:\(pass!)")
return self.client.login(accont: user!, password: pass!)
}.bind(to: ctr.finishbserver)
上述代码段将用户名和密码最后一个值进行和处理生成了一组新的observerable
Driver
driver与observerable在功能上它类似被观察者(Observable),而它本身也可以与转换成被观察者(Observable: asDriver, Driver: asObservable),他不可以发送err事件 所以一旦发生错误会有容错处理(onErrorJustReturn: "")
Driver序列不允许发出error,
Driver序列的监听只会在主线程中。
所以Driver是专为UI绑定量身打造的东西。
以下情况你可以使用Driver替换BindTo:
不能发出error;
在主线程中监听;
共享事件流;
BehaviorSubject
/// Represents a value that changes over time.
///
/// Observers can subscribe to the subject to receive the last (or initial) value and all subsequent notifications.
他既可以当做观察者也可以当做被观察者
具体可以参考Rxswift的subject
网友评论