美文网首页
RxSwift - 特征观察者

RxSwift - 特征观察者

作者: aven_kang | 来源:发表于2022-07-04 19:16 被阅读0次
和 Observable 一样,观察者也存特征观察者,例如:
·Binder

AnyObserver

AnyObserver 可以用来描叙任意一种观察者。

用例

URLSession.shared.rx.data(request: URLRequest(url: URL.init(string: "https://api.github.com/repos/")!)).subscribe { data in
            
        } onError: { error in
            
        } onCompleted: {
            
        }.disposed(by: disposeBag)

可以看作

let observer: AnyObserver<Data> = AnyObserver {
            (event) in
            switch event {
            case .next(let data):
                print("data")
            case .error(let error):
                print("error")
            case .completed:
                print("completed")
            }
        }

使用observer

 URLSession.shared.rx.data(request: URLRequest(url: URL.init(string: "https://api.github.com/repos/")!)).subscribe(observer)
            .disposed(by: disposeBag)

用例2

 let passwordVaild = passwordTextFiled.rx.text.orEmpty
            .map {
                $0.count >= minimalPasswordLength
            }
            .share(replay: 1)
 let observer1: AnyObserver<Bool> = AnyObserver {
            (evnt) in
            switch evnt {
            case .next(let isHidden):
                self.passwordVaildLb.isHidden = isHidden
            default:
                break
            }
        }
passwordVaild.bind(to: observer1)
            .disposed(by: disposeBag)

Binder

Binder 主要有以下两个特征: 不会处理错误事件 确保绑定都是在给定 Scheduler 上执行(默认MainScheduler ) 一旦产生错误事件,在调试环境下将执行 fatalError ,在 发布环境下将打印错误信息。

 let observer1: AnyObserver<Bool> = AnyObserver {
            (evnt) in
            switch evnt {
            case .next(let isHidden):
                self.passwordVaildLb.isHidden = isHidden
            default:
                break
            }
        }
passwordVaild.bind(to: observer1)
            .disposed(by: disposeBag)

由于这个观察者是一个 UI 观察者,所以它在响应事件时, 只会处理 next 事件,并且更新 UI 的操作需要在主线程上 执行。 因此一个更好的方案就是使用 Binder :

let observer2: Binder<Bool> = Binder(passwordVaildLb) { (view, isHidden) in
            view.isHidden = isHidden
        }
        
passwordVaild
    .bind(to: observer2)
    .disposed(by: disposeBag)

Binder 可以只处理 next 事件,并且保证响应 next 事件 的代码一定会在给定 Scheduler 上执行,这里采用默认的
MainScheduler 。

复用

由于页面是否隐藏是一个常用的观察者,所以应该让所有的UIView 都提供这种观察者:
extension Reactive where Base: UIView {
    
    public var isHidden: Binder<Bool> {
        return Binder(self.base) { view, isHidden in
            view.isHidden = isHidden
        }
    }
}
        passwordTextFiled.rx.text.orEmpty
            .map{$0.count >= minimalUsernameLength}
            .bind(to: passwordVaildLb.rx.isHidden)
            .disposed(by: disposeBag)

这样你不必为每个 UI 控件单独创建该观察者。这就是
passwordVaildLb.rx.isHidden的由来,许多 UI 观察 者 都是这样创建的:

·按钮是否可点击 button.rx.isEnabled:
extension Reactive where Base: UIControl {
    
    public var isEnable: Binder<Bool> {
        return Binder<self.base> { control, value in
            control.isEnable = value
        }
    }
}
·label 的当前文本 label.rx.text :
extension Reactive where Base: UILabel {
    
    public var text: Binder<String?> {
        return Binder(self.base) { lable, text in
            lable.text = text
        }
    }
}

Observable & Observer 既是可监听序 列也是观察者

在我们所遇到的事物中,有一部分非常特别。它们既是可监 听序列也是观察者。 例如: textField 的当前文本。它可以看成是由用户输入, 而产生的一个文本序列。也可以是由外部文本序列,来控制 当前显示内容的观察者:

// 作为可监听序列
let observable = textField.rx.text
observable.subscribe(onNext: { text in show(text:
text) })
// 作为观察者
let observer = textField.rx.text
let text: Observable<String?> = ...
text.bind(to: observer)

有许多 UI 控件都存在这种特性,例如: switch 的开关状 态, segmentedControl 的选中索引号, datePicker 的选中 日期等等。

框架里面定义了一些辅助类型,它们既是可监听序列 也是观察者。如果你能合适的应用这些辅助类型,它们就可 以帮助你更准确的描述事物的特征:
  • AsyncSubject
  • PublishSubject
  • ReplaySubject
  • BehaviorSubject
  • ControlProperty

AsyncSubject

AsyncSubject 将在源 Observable 产生完成事件后,发出最 后一个元素(仅仅只有最后一个元素),如果源Observable 没有发出任何元素,只有一个完成事件。那AsyncSubject 也只有一个完成事件。

 let subject = AsyncSubject<String>()
        
        subject.subscribe { string in
            print(string)
        }.disposed(by: disposeBag)
        
        subject.onNext("1")
        subject.onNext("2")
        subject.onNext("3")
        subject.onCompleted()
//打印
next(3)
completed

PublishSubject

PublishSubject 将对观察者发送订阅后产生的元素,而在订阅 前发出的元素将不会发送给观察者。如果你希望观察者接收 到所有的元素,你可以通过使用 Observable 的 create 方 法来创建 Observable ,或者使用 ReplaySubject。

let subject = PublishSubject<String>()
        subject.subscribe { event in
            print("Subscription: 1 Event:",event)
        }.disposed(by: disposeBag)
        
        subject.onNext("1")
        subject.onNext("2")
        
   subject.subscribe { event in
            print(print("Subscription: 2 Event:",event))
        }.disposed(by: disposeBag)
        
        subject.onNext("1")
        subject.onNext("2")

打印结果

Subscription: 1 Event: next(1)
Subscription: 1 Event: next(2)
Subscription: 1 Event: next(1)
Subscription: 2 Event: next(1)
()
Subscription: 1 Event: next(2)
Subscription: 2 Event: next(2)
()

ReplaySubject

ReplaySubject 将对观察者发送全部的元素,无论观察者是何 时进行订阅的。 这里存在多个版本的 ReplaySubject ,有的只会将最新的 n 个 元素发送给观察者,有的只会将限制时间段内最新的元素发 送给观察者。
如果把 ReplaySubject 当作观察者来使用,注意不要在多个 线程调用 onNext , onError 或 onCompleted 。这样会导 致无序调用,将造成意想不到的结果。

 let subject = ReplaySubject<String>.create(bufferSize: 1)
        
     subject.subscribe { event in
            print(print("Subscription: 1 Event:",event))
        }.disposed(by: disposeBag)
        
        subject.onNext("1")
        subject.onNext("2")
        
     subject.subscribe { event in
            print(print("Subscription: 2 Event:",event))
        }.disposed(by: disposeBag)
        
        subject.onNext("1")
        subject.onNext("2")

打印

Subscription: 1 Event: next(1)
()
Subscription: 1 Event: next(2)
()
Subscription: 2 Event: next(2)
()
Subscription: 1 Event: next(1)
()
Subscription: 2 Event: next(1)
()
Subscription: 1 Event: next(2)
()
Subscription: 2 Event: next(2)
()

BehaviorSubject

当观察者对 BehaviorSubject 进行订阅时,它会将源
Observable 中最新的元素发送出来(如果不存在最新的元 素,就发出默认元素)。然后将随后产生的元素发送出来。
如果源 Observable 因为产生了一个 error 事件而中止,BehaviorSubject 就不会发出任何元素,而是将这个 error事件发送出来。

        let disposeBag = DisposeBag()
        let subject = BehaviorSubject(value: "🔴")
        subject
         .subscribe { print("Subscription: 1 Event:", $0) }
         .disposed(by: disposeBag)
        subject.onNext("🐶")
        subject.onNext("🐱")

        subject
         .subscribe { print("Subscription: 2 Event:", $0) }
         .disposed(by: disposeBag)
        subject.onNext("🅰 ")
        subject.onNext("🅱 ")

        subject
         .subscribe { print("Subscription: 3 Event:", $0) }
         .disposed(by: disposeBag)
        subject.onNext(" ")
        subject.onNext("🍊")
Subscription: 1 Event: next(🔴)
Subscription: 1 Event: next(🐶)
Subscription: 1 Event: next(🐱)
Subscription: 2 Event: next(🐱)
Subscription: 1 Event: next(🅰 )
Subscription: 2 Event: next(🅰 )
Subscription: 1 Event: next(🅱 )
Subscription: 2 Event: next(🅱 )
Subscription: 3 Event: next(🅱 )
Subscription: 1 Event: next( )
Subscription: 2 Event: next( )
Subscription: 3 Event: next( )
Subscription: 1 Event: next(🍊)
Subscription: 2 Event: next(🍊)
Subscription: 3 Event: next(🍊)

相关文章

网友评论

      本文标题:RxSwift - 特征观察者

      本文链接:https://www.haomeiwen.com/subject/wwmcbrtx.html