RxSwfit 学习笔记(九) Schedulers调度器及其操作符应用 subscribeOn & observeOn

813 阅读3分钟

实力吐槽官方文档的案例,让人看着很困惑!

Schedulers - 调度器

SchedulersRx 实现多线程的核心模块,它主要用于控制任务在哪个线程或队列运行。

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,来控制同时执行并发任务的最大数量。