RxSwift核心之Observer

简介

观察者 (Observer) 的作用就是监听事件,然后对这个事件做出响应,或者说任何响应事件的行为都是观察者。比如:

  • 当前视频播放到30分钟时,弹出视频小剧场(广告),后者就是 观察者
  • 当前温度高于30度,打开空调降温,后者就是 观察者
  • 当你点击视频拍摄时,系统弹出弹框问你是否同意使用摄像头,后者就是 观察者
  • ······

eg:

tap.subscribe(onNext: { [weak self] in
    self?.showAlert()
}, onError: { error in
    print("发生错误: \(error.localizedDescription)")
}, onCompleted: {
    print("任务完成")
})

在这里,弹出提示框就是 观察者
创建观察者最直接的方法就是在 Observablesubscribe 方法后面描述,事件发生时,需要如何做出响应。而观察者就是由后面的 onNextonErroronCompleted 的这些闭包构建出来的。此外,我们还有AnyObserverBinder 方式创建观察者。

AnyObserver

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

  • 打印网络请求结果
URLSession.shared.rx.data(request: URLRequest(url: url))
    .subscribe(onNext: { data in
        print("Data Task Success with count: \(data.count)")
    }, onError: { error in
        print("Data Task Error: \(error)")
    })
    .disposed(by: disposeBag)

可以看作是:

let observer: AnyObserver<Data> = AnyObserver { (event) in
    switch event {
    case .next(let data):
        print("Data Task Success with count: \(data.count)")
    case .error(let error):
        print("Data Task Error: \(error)")
    default:
        break
    }
}

URLSession.shared.rx.data(request: URLRequest(url: url))
    .subscribe(observer)
    .disposed(by: disposeBag)
  • 打印网络请求结果
usernameValid
    .bind(to: usernameValidOutlet.rx.isHidden)
    .disposed(by: disposeBag)

可以看作是:

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)

Binder

基本介绍
1、相较于 AnyObserver 的大而全,Binder 更专注于特定的场景。Binder 主要有以下两个特征:

  • 不会处理错误事件
  • 确保绑定都是在给定 Scheduler 上执行(默认 MainScheduler

2、一旦产生错误事件,在调试环境下将执行 fatalError,在发布环境下将打印错误信息。

eg:

import RxSwift
import RxCocoa
 
@IBOutlet weak var lable: UILabel!

func test() {
        let disposeBag = DisposeBag()
        
        // 观察者
        let observer: AnyObserver<String> = AnyObserver { [weak self] (event) in
            switch event {
            case .next(let text):
                // 收到发出的索引数后显示到label上
                self?.lable.text = text
            default:
                break
            }
        }
         
        // Observable序列(just:创建一个序列,只包含一个元素)
        let observable = Observable<Int>.just(100)
        observable.map { (index) -> String in
            return "当前索引数:\(index)"
        }.observeOn(MainScheduler.instance).bind(to: observer).disposed(by: disposeBag)
    }

在上面示例代码中,label 标签的文字显示就是一个典型的 UI 观察者。它在响应事件时,只会处理 next 事件,而且更新 UI 的操作需要在主线程上执行。那么这种情况下更好的方案就是使用 Binder,代码如下:

import RxSwift
import RxCocoa
 
@IBOutlet weak var lable: UILabel!

func test() {
        let disposeBag = DisposeBag()
        
        // 观察者
        let observer: Binder<String> = Binder(lable) { (view, text) in
            // 收到发出的索引数后显示到label上
            view.text = text
        }
             
        // Observable序列(just:创建一个序列,只包含一个元素)
        let observable = Observable<Int>.just(100)
        observable.map { (index) -> String in
            return "当前索引数:\(index)"
            }.observeOn(MainScheduler.instance).bind(to: observer).disposed(by: disposeBag)
     }

附:BinderRxCocoa 中的应用
1、其实 RxCocoa 在对许多 UI 控件进行扩展时,就利用 Binder 将控件属性变成观查者,比如 UIControl+Rx.swift 中的 isEnabled 属性便是一个 observer

import RxSwift
import UIKit
 
extension Reactive where Base: UIControl {
     
    // Bindable sink for `enabled` property.
    public var isEnabled: Binder<Bool> {
        return Binder(self.base) { control, value in
            control.isEnabled = value
        }
    }
}

2、因此我们可以将序列直接绑定到它上面。比如下面样例,就可以用来判断 button 可用 / 不可用

@IBOutlet weak var button: UIButton!

@IBAction func buttonClick(_ sender: UIButton) {
        print("点击了按钮")
    }

func test() {
        let disposeBag = DisposeBag()
        
        let observable = Observable<Int>.just(100)
        
        observable.map { (e) -> Bool in
            return (e != 100)
            }.observeOn(MainScheduler.instance).bind(to: button.rx.isEnabled).disposed(by: disposeBag)
    }

Author

如果你有什么建议,可以关注我的公众号:iOS开发者进阶,直接留言,留言必回。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容