observeOn 与 subscribeOn

原文:observeOn vs. subscribeOn

跨线程订阅是 RxSwift Slack 频道上反复出现的一个问题。解释非常简单,所以我觉得把它放在 Blog 中是个好主意,这样无论何时需要,我都可以链接到它,而不用一遍又一遍地输入所有内容。

Observable 订阅

有关订阅(subscribing)和观察(observing)的术语在我看来有点混乱,所以我们先把这个问题解决掉(不要跳过这一部分!)。

  1. 首先,你需要定义一个 Observable,在某些情况下,你需要在闭包中提供一些代码来执行工作并向任何观察者发送元素。当你创建 Observable 时,这些代码会被保存起来,以备将来使用,但不会 立即执行。如果还没有观察者------ Observable 只是静静地等待,不会做任何事情。
  2. 当你为订阅建模时,您可以使用一些操作符(如 map、filter 等)来处理发射的元素。添加操作符仍然不会执行任何工作------你只是在原始可观察对象的基础上创建了一个 "更专业" 的可观察对象。
  3. 只有在调用可观察对象的 subscribe(...) 方法时,才能 "启动" 可观察对象。调用 subscribe(...) 将实际执行你在第一部分(上文)代码块中提供的代码。

因此,从这个意义上讲,这里有两个要点需要说明:

  • subscription code 是通过 subscribe() 调用的代码,并且位于 Observable.create { ...} 中。这是创建订阅并生成元素的代码。
  • observation code 是你观察发射元素的地方 - 这是你在 onNext: {...}, onCompleted:{...} 等中提供的代码。这是你进行观察的地方。

💡 我们用 subscribeOn 来决定数据序列的构建函数在哪个 Scheduler 上运行。
💡 我们用 observeOn 来决定在哪个 Scheduler 监听这个数据序列。

Schedulers

RxSwift 自带了大量预定义调度程序,可以满足大多数情况下的需求。在 RxSwift 软件仓库中有一个关于此主题的简短文档:schedulers。

4.6 Schedulers - 调度器 · RxSwift 中文文档

本文将使用两个调度程序:

  • MainScheduler.instance:调度程序在主线程上执行;
  • ConcurrentDispatchQueueScheduler:使用 GCD 在给定队列上执行工作;

Subscribing 和 subscribeOn

让我们来看看 subscribeOn 操作符------它允许你更改执行 subscription code 的 Schedulers。

默认情况下,订阅代码将在与调用 subscribe() 代码的相同线程上运行,除非使用 subscribeOn (...) 改变上下文。

例如:

swift 复制代码
Observable<Int>.create { observer in
    observer.onNext(1)
    sleep(1)
    observer.onNext(2)
    return Disposables.create()
}
.subscribe(onNext: { el in
    print(Thread.isMainThread)
})

如果将此代码放在 viewDidLoad 中,由于订阅代码(subscription code)中使用了 sleep,因此会阻塞主线程。

你的 onNext 代码将打印为 true,因为你将始终停留在主线程上:

scss 复制代码
[main] subscribe() -> [main] create{ ... } -> [main] onNext { ... }

现在,你可以通过插入 subscribeOn 操作符来更改订阅的 scheduler:

swift 复制代码
Observable<Int>.create { observer in
    observer.onNext(1)
    sleep(1)
    observer.onNext(2)
    return Disposables.create()
}
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background))
.subscribe(onNext: { el in
    print(Thread.isMainThread)
})

这一次,你将在订阅的同时切换线程:

scss 复制代码
[main] subscribe() -> [background] create{ ... } -> [background] onNext { ... }

而 onNext 中的打印将输出 false。

Observing 和 observeOn

现在我们来观察序列中的元素。这部分涉及 observation code。

在我们之前的示例中,你将订阅切换到了后台队列,因为它做了一些阻塞性工作。但实际上,你想要的是在主线程上运行 onNext {...} 中的代码,以便更新应用程序的用户界面。

这可以通过使用 observeOn 操作符来实现。顺便说一下,你可以将 observeOn 和 subscribeOn 放在操作符链中的任何位置,顺序并不重要。

RxSwift 包含一个共享调度器,它使用主线程 MainScheduler.instance,因此你可以像这样使用它来轻松观察元素:

swift 复制代码
Observable<Int>.create { observer in
    observer.onNext(1)
    sleep(1)
    observer.onNext(2)
    return Disposables.create()
}
.observeOn(MainScheduler.instance) // 在主线程监听
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .background)) // 在后台线程创建订阅
.subscribe(onNext: { el in
    print(Thread.isMainThread)
})

这将像这样执行代码:

scss 复制代码
[main] subscribe() -> [background] create{ ... } -> [main] onNext { ... }

如果你经常做异步工作,就会经常用到这种模式,因此越早习惯越好。

我希望这篇文章能让大家对命名和用法有更清晰的认识。

相关推荐
2501_916007472 天前
Windows OpenSSL 生成 iOS 证书,制作 p12 与描述文件,KXBuild 签名实操
windows·vscode·ios·objective-c·个人开发·swift·敏捷流程
00后程序员张2 天前
Windows 开发 iOS App 入门,用 SwiftUI 写第一个 iOS App 装到 iPhone
ide·vscode·ios·objective-c·个人开发·swift·敏捷流程
andyweike3 天前
Swift
开发语言·ios·swift
静以修身zzz3 天前
OpenStack对象存储-Swift、OpenStack编排管理-heat、OpenStack网络管理-neutron
linux·运维·服务器·架构·openstack·swift
瓦瓦gogo4 天前
第一次了解 iOS 开发:从 Swift、SwiftUI 到公共组件
ios·swiftui·swift
青峰讲运维5 天前
OpenStack 存储深度解析|Cinder 块存储 + Swift 对象存储原理与完整实操(Yoga)
开发语言·openstack·swift
2501_915106325 天前
Windows 上开发 Unity iOS,使用 KXBuild 进行真机调试、性能采样与打包 ipa
windows·vscode·unity·ios·个人开发·swift·敏捷流程
2501_915918416 天前
Windows 上开发 React Native iOS,真机调试、Fast Refresh 与打包 ipa
windows·vscode·react native·ios·个人开发·swift·敏捷流程
szp20057 天前
中文字幕烧进视频后整片空白:CoreText 低报行高,导出照样成功
ios·swift
2501_915106327 天前
iOS 单元测试怎么跑?用 KXApp 在 VS Code 里跑 XCTest 和 Swift Testing
ide·vscode·ios·单元测试·个人开发·swift·敏捷流程