A-A+

Combine-Scheduler

2020年05月16日 iOS原创文章 暂无评论
博客主机

如果说 Publisher 决定了发布什么样的 (what) 数据的话,Scheduler(调度器) 所要解决的就是两个问题:在什么地方 (where),以及在什么时候 (when) 来发布数据和接收数据。我们都知道,在 iOS 开发中如果需要更新 UI,需要保证相关操作发生在主线程。在 Combine 中如果数据流前面的 Publisher 是在后台线程进行操作,那么在订阅时,当状态的变化会更新 UI 时,需要将数据流中接收数据的线程切换到主线程。

内置Scheduler

Scheduler在是一个协议,遵守了该协议的内置 Scheduler 有:

  • DispatchQueue
  • OperationQueue
  • RunLoop
  • ImmediateScheduler:立即执行同步操作, 如果使用它执行延迟的工作,会报错。

使用RunLoop.mainDispatchQueue.mainOperationQueue.main来执行与 UI 相关的操作。

receive与subscribe

默认情况下,当前的 Scheduler 与最初产生数据的 Publisher 所在的 Scheduler 相同。但是实际情况往往是在整个数据流中需要切换 Scheduler,所以 Combine 提供了两个函数来设置 Scheduler。

receive(on:)

定义了在哪个 Scheduler 完成 Publisher 的订阅。(在哪里接收数据

import Combine

let subscription = Just(1)
    .map { _ in print(Thread.isMainThread) } 
    .receive(on: DispatchQueue.global())
    .map { print(Thread.isMainThread) }
    .sink { print(Thread.isMainThread) }

/* 输出
 true
 false
 false
 */

subscribe(on:)

定义了在哪个 Scheduler 来发布 Publisher,它的位置顺序不会影响结果。(在哪里发布数据

import Combine

let subscription = Just(1)
    .subscribe(on: DispatchQueue.global())
    .map { _ in print(Thread.isMainThread) } 
    .sink { print(Thread.isMainThread) }

/* 输出
false
false
*/

let subscription = Just(1)
    .subscribe(on: DispatchQueue.global())
    .map { _ in print(Thread.isMainThread) }
    .receive(on: DispatchQueue.main)
    .sink { print(Thread.isMainThread) }

/* 输出
false
true
*/

案例

import UIKit
import Combine

let subscription = URLSession.shared
    .dataTaskPublisher(for: URL(string: "https://www.example.com")!)
    .compactMap { String(data: $0.data, encoding: .utf8) }
    .receive(on: RunLoop.main) // 回到主线程更新UI
    .sink {
        textView.text = $0
    }

给我留言

Copyright © ios教程,苹果粉丝,苹果资讯,ios入门教程,ios学习,ios程序员,ios视频教程,ios粉丝网 保留所有权利.   Theme  Ality

用户登录