Observer - 观察者
https://beeth0ven.github.io/RxSwift-Chinese-Documentation/content/rxswift_core/observer.html
观察者 是用来监听事件,然后它需要这个事件做出响应。例如:弹出提示框就是观察者,它对点击按钮这个事件做出响应。
如何创建观察者
和 Observable 一样,框架已经帮我们创建好了许多常用的观察者。例如:view
是否隐藏,button
是否可点击, label
的当前文本,imageView
的当前图片等等。另外,有一些自定义的观察者是需要我们自己创建的。
tap.subscribe(onNext: { [weak self] in
self?.showAlert()
}, onError: { error in
print("发生错误: \(error.localizedDescription)")
}, onCompleted: {
print("任务完成")
})
创建观察者最直接的方法就是在 Observable
的 subscribe
方法后面描述,事件发生时,需要如何做出响应。而观察者就是由后面的 onNext
,onError
,onCompleted
的这些闭包构建出来的。
以上是创建观察者最常见的方法。当然你还可以通过其他的方式来创建观察者,详见 AnyObserver
AnyObserver
public protocol ObserverType {
...
...
}
public struct AnyObserver<Element> : ObserverType {
...
...
}
AnyObserver 可以用来描叙任意一种观察者。
创建方式:
let observer: AnyObserver<Element> = AnyObserver.init { (event) in
switch event {
case .next(let value):
// 序列处理
case .error(let error):
// error
case .completed:
// 完成
}
}
eg:
准备代码:
func getObservable(with url: String) -> Observable<JSON> {
return Observable<JSON>.create { (observer) -> Disposable in
guard let url = URL.init(string: url) else {
let err = TError.init(errorCode: 10, errorString: "url error", errorData: nil)
observer.onError(err)
return Disposables.create()
}
let request = URLRequest.init(url: url)
let task = URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) in
if let err = error {
observer.onError(err)
return
}
guard let jsonData = data, let jsonObj = try? JSONSerialization.jsonObject(with: jsonData, options: .mutableLeaves) else {
let err = TError.init(errorCode: 11, errorString: "json error", errorData: data)
observer.onError(err)
return
}
observer.onNext(jsonObj)
observer.onCompleted()
})
task.resume()
return Disposables.create {
task.cancel()
}
}
}
以前的做法:
func theGeneralPractice() {
getObservable(with: "https://api.github.com/")
.subscribe(onNext: { (jsonObj) in
print("Get JSON success")
guard JSONSerialization.isValidJSONObject(jsonObj) else { return }
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObj, options: .prettyPrinted) {
let jsonStr = String.init(data: jsonData, encoding: String.Encoding.utf8)
print(jsonStr ?? "")
}
}, onError: { (error) in
if let error = error as? TError {
error.printLog()
} else {
print(error.localizedDescription)
}
}, onCompleted: {
print("completed")
})
.disposed(by: disposeBag)
}
相当于:
func testCreateObserver() {
let observer: AnyObserver<JSON> = AnyObserver.init { (event) in
switch event {
case .next(let jsonObj):
print("Get JSON success")
guard JSONSerialization.isValidJSONObject(jsonObj) else { return }
if let jsonData = try? JSONSerialization.data(withJSONObject: jsonObj, options: .prettyPrinted) {
let jsonStr = String.init(data: jsonData, encoding: String.Encoding.utf8)
print(jsonStr ?? "")
}
case .error(let error):
if let err = error as? TError {
err.printLog()
} else {
print(error.localizedDescription)
}
case .completed:
print("completed")
}
}
getObservable(with: "https://api.github.com/")
.subscribe(observer)
.disposed(by: disposeBag)
}
Binder
https://beeth0ven.github.io/RxSwift-Chinese-Documentation/content/rxswift_core/observer/binder.html
public protocol ObserverType {
...
...
}
public struct Binder<Value>: ObserverType {
...
...
}
Binder 主要有以下两个特征:
- 不会处理错误事件
- 确保绑定都是在给定 [Scheduler] 上执行(默认 MainScheduler)
一旦产生错误事件,在调试环境下将执行 fatalError
,在发布环境下将打印错误信息。
示例
在介绍 AnyObserver
时,我们举了这样一个例子:
let observer: AnyObserver<Bool> = AnyObserver { [weak self] (event) in
switch event {
case .next(let isHidden):
self?.usernameValidOutlet.isHidden = isHidden
default:
break
}
}
usernameValid
.bind(to: observer)
.disposed(by: disposeBag)
由于这个观察者是一个 UI 观察者,所以它在响应事件时,只会处理 next
事件,并且更新 UI 的操作需要在主线程上执行。
因此一个更好的方案就是使用 Binder:
let observer: Binder<Bool> = Binder(usernameValidOutlet) { (view, isHidden) in
view.isHidden = isHidden
}
usernameValid
.bind(to: observer)
.disposed(by: disposeBag)
Binder 可以只处理 next
事件,并且保证响应 next
事件的代码一定会在给定 [Scheduler] 上执行,这里采用默认的 MainScheduler。
复用
由于页面是否隐藏是一个常用的观察者,所以应该让所有的 UIView
都提供这种观察者:
extension Reactive where Base: UIView {
public var isHidden: Binder<Bool> {
return Binder(self.base) { view, hidden in
view.isHidden = hidden
}
}
}
usernameValid
.bind(to: usernameValidOutlet.rx.isHidden)
.disposed(by: disposeBag)
这样你不必为每个 UI 控件单独创建该观察者。这就是 usernameValidOutlet.rx.isHidden
的由来,许多 UI 观察者 都是这样创建的:
按钮是否可点击
button.rx.isEnabled
:extension Reactive where Base: UIControl { public var isEnabled: Binder<Bool> { return Binder(self.base) { control, value in control.isEnabled = value } } }
label
的当前文本label.rx.text
:extension Reactive where Base: UILabel { public var text: Binder<String?> { return Binder(self.base) { label, text in label.text = text } } }
你也可以用这种方式来创建自定义的 UI 观察者。
eg:
准备代码:
func getImage() -> Observable<UIImage> {
return Observable<UIImage>.create { (observer) -> Disposable in
let downloadToken = SDWebImageDownloader.shared().downloadImage(
with: URL.init(string: "https://avatars1.githubusercontent.com/u/11990850"),
options: SDWebImageDownloaderOptions.highPriority,
progress: nil,
completed: { (image, data, error, finished) in
if let img = image {
observer.onNext(img)
observer.onCompleted()
return
}
if let err = error {
observer.onError(err)
return
}
observer.onError(TError.init(errorCode: 10, errorString: "UNKNOW ERROR", errorData: data))
}
)
return Disposables.create {
SDWebImageDownloader.shared().cancel(downloadToken)
}
}
}
之前的调用方式:
getImage().asDriver(onErrorJustReturn: #imageLiteral(resourceName: "placeholderImg"))
.drive(imageView.rx.image)
.disposed(by: disposeBag)
其中 imageView.rx.image
定义中有 Binder
的定义:
extension Reactive where Base: UIImageView {
/// Bindable sink for `image` property.
public var image: Binder<UIImage?> {
return Binder(base) { imageView, image in
imageView.image = image
}
}
}
相当于:
func testCreateImageViewBinderObserver() {
let observer: Binder<UIImage> = Binder.init(imageView) { (imageView, image) in
imageView.image = image
}
getImage()
.asDriver(onErrorJustReturn: #imageLiteral(resourceName: "placeholderImg"))
.drive(observer)
.disposed(by: disposeBag)
// getImage()
// .observeOn(MainScheduler.instance)
// .bind(to: observer)
// .disposed(by: disposeBag)
}
总结
AnyObserver
let observer: AnyObserver<Element> = AnyObserver.init { (event) in
switch event {
case .next(let value):
// 序列处理
case .error(let error):
// error
case .completed:
// 完成
}
}
someObservableVar.subscribe(observer).disposed(by: disposeBag)
Binder
let observer: Binder<UIImage> = Binder.init(imageView) { (imageView, image) in
imageView.image = image
}
let placeholderImage = #imageLiteral(resourceName: "placeholderImg")
someImageObservableVar.asDriver(onErrorJustReturn: placeholderImage).drive(observer).disposed(by: disposeBag)
// 或
// someImageObservableVar.observeOn(MainScheduler.instance).bind(to: observer).disposed(by: disposeBag)