实力吐槽官方文档的案例,让人看着很困惑!
Schedulers - 调度器
Schedulers 是 Rx 实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行。
subscribeOn
我们用 subscribeOn 来决定数据序列的构建函数在哪个 Scheduler 上运行。以上例子中,由于获取 Data 需要花很长的时间,所以用subscribeOn切换到 后台Scheduler来获取Data。这样可以避免主线程被阻塞。
observeOn
我们用 observeOn 来决定在哪个 Scheduler 监听这个数据序列。以上例子中,通过使用 observeOn 方法切换到主线程来监听并且处理结果。
一个比较典型的例子就是,在后台发起网络请求,然后解析数据,最后在主线程刷新页面。你就可以先用 subscribeOn切到后台去发送请求并解析数据,最后用 observeOn 切换到主线程更新页面。
官方案例
如果你曾经使用过 GCD, 那你对以下代码应该不会陌生:
// 后台取得数据,主线程处理结果
DispatchQueue.global(qos: .userInitiated).async {
let data = try? Data(contentsOf: url)
DispatchQueue.main.async {
self.data = data
}
}
如果用 RxSwift 来实现,大致是这样的:
let rxData: Observable<Data> = ...
rxData
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .userInitiated))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { [weak self] data in
self?.data = data
})
.disposed(by: disposeBag)
这个案例让人看着有点困惑。对初学者一点都不友好,还需要到处找资料。
我这另外提供一个案例,更容易理解。
众所周知,如果我们一次性加载很多图片,是需要开启线程去加载才不会造成主线程堵塞的。 那么我这就提供一个加载图片开启线程的案例。
加载图片案例
import UIKit
import RxSwift
import RxCocoa
class TenthViewController: UIViewController {
let dis = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
//初始化一个tableView
let table = UITableView.init(frame: view.bounds, style: .plain)
table.delegate = self
table.dataSource = self
self.view = table
}
}
extension TenthViewController:UITableViewDelegate,UITableViewDataSource{
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 200
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCell(withIdentifier: "cell")
if cell == nil {
cell = UITableViewCell.init(style: .default, reuseIdentifier: "cell")
}
//使用调度器
Observable<UIImage>.create { (observer) -> Disposable in
let url:URL = URL.init(string: "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1567402318825&di=5539a984812ea4236e4627efd47eb467&imgtype=0&src=http%3A%2F%2Fs9.sinaimg.cn%2Fbmiddle%2F005XWbeUgy6QwbUP4QE58%26690")!
let imageData = try! Data.init(contentsOf: url)
let image = UIImage.init(data: imageData)
observer.onNext(image!)
return Disposables.create()
}
.subscribeOn(ConcurrentDispatchQueueScheduler(qos: .default))
.observeOn(MainScheduler.instance)
.subscribe(onNext: { image in
cell?.imageView?.image = image
}).disposed(by: dis)
//使用正常的GCD
// DispatchQueue.global(qos: .default).async {
// let url:URL = URL.init(string: "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1567402318825&di=5539a984812ea4236e4627efd47eb467&imgtype=0&src=http%3A%2F%2Fs9.sinaimg.cn%2Fbmiddle%2F005XWbeUgy6QwbUP4QE58%26690")!
// let image = UIImage.init(data: try! Data.init(contentsOf: url))
// DispatchQueue.main.async {
// cell?.imageView?.image = image
// }
// }
return cell!
}
}
MainScheduler
MainScheduler 代表主线程。如果你需要执行一些和 UI 相关的任务,就需要切换到该 Scheduler 运行。
SerialDispatchQueueScheduler
SerialDispatchQueueScheduler抽象了串行 DispatchQueue。如果你需要执行一些串行任务,可以切换到这个Scheduler运行。
ConcurrentDispatchQueueScheduler
ConcurrentDispatchQueueScheduler 抽象了并行 DispatchQueue。如果你需要执行一些并发任务,可以切换到这个Scheduler运行。
OperationQueueScheduler
OperationQueueScheduler 抽象了NSOperationQueue。
它具备NSOperationQueue 的一些特点,例如,你可以通过设置 maxConcurrentOperationCount,来控制同时执行并发任务的最大数量。