自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

我們一起了解 Swift 調(diào)度器

移動開發(fā) iOS
iOS 應(yīng)用開發(fā)中最常見的錯(cuò)誤之一是線程錯(cuò)誤,當(dāng)開發(fā)者試圖從一個(gè)閉包中更新用戶界面時(shí),會出現(xiàn)這種錯(cuò)誤。為了解決這個(gè)問題,我們可以使用 DispatchQueue.main 和 threads。

[[413583]]

本文轉(zhuǎn)載自微信公眾號「Swift社區(qū)」,作者前端小工  。轉(zhuǎn)載本文請聯(lián)系Swift社區(qū)公眾號。

前言

iOS 應(yīng)用開發(fā)中最常見的錯(cuò)誤之一是線程錯(cuò)誤,當(dāng)開發(fā)者試圖從一個(gè)閉包中更新用戶界面時(shí),會出現(xiàn)這種錯(cuò)誤。為了解決這個(gè)問題,我們可以使用 DispatchQueue.main 和 threads。

在本教程中,我們將學(xué)習(xí)什么是調(diào)度器,以及我們?nèi)绾卧趇OS應(yīng)用開發(fā)中使用它們來管理隊(duì)列和循環(huán)。之前對 Swift、Combine 框架和 iOS 開發(fā)的知識是必要的。

讓我們開始吧!

什么是調(diào)度器?

根據(jù)調(diào)度器的文檔[1],調(diào)度器是 "一個(gè)定義何時(shí)何地執(zhí)行一個(gè)閉包的協(xié)議"。從本質(zhì)上講,調(diào)度器為開發(fā)者提供了一種在特定安排下執(zhí)行代碼的方式,有助于在應(yīng)用程序中運(yùn)行隊(duì)列命令。

開發(fā)人員可以通過使用調(diào)度器將大批量的操作遷移到二級隊(duì)列中,釋放出應(yīng)用程序主隊(duì)列的空間,并更新應(yīng)用程序的用戶界面。

調(diào)度器還可以優(yōu)化并行執(zhí)行命令的代碼,允許開發(fā)者在同一時(shí)間執(zhí)行更多的命令。如果代碼是串行的,開發(fā)者可以一次執(zhí)行一個(gè)位的代碼。

調(diào)度器的類型

有幾種類型的調(diào)度器是Combine 內(nèi)置的[2]。值得注意的是,調(diào)度器遵循調(diào)度器協(xié)議,這可以在上面鏈接的調(diào)度器文檔中找到。

讓我們看一下幾個(gè)流行的調(diào)度器

OperationQueue

根據(jù)其文件,一個(gè) OperationQueue 會根據(jù)命令的優(yōu)先級和準(zhǔn)備程度來執(zhí)行命令。一旦你把一個(gè)操作添加到隊(duì)列中,該操作將保持在其隊(duì)列中,直到它完成執(zhí)行其命令。

一個(gè) OperationQueue,可以以串行或并行的方式執(zhí)行任務(wù),這取決于任務(wù)本身。OperationQueue 主要用于后臺任務(wù),如更新應(yīng)用程序的用戶界面。

DispatchQueue

蘋果公司的文檔將一個(gè) DispatchQueue[3]是一個(gè)先入先出的隊(duì)列,它可以接受塊對象形式的任務(wù),并以串行或并發(fā)的方式執(zhí)行它們。

系統(tǒng)會在一個(gè)線程池上管理提交給 DispatchQueue 的工作。除非 DispatchQueue 代表一個(gè)應(yīng)用程序的主線程,否則 DispatchQueue 并不保證它將使用哪個(gè)線程來執(zhí)行一個(gè)任務(wù)。

DispatchQueue 經(jīng)常被認(rèn)為是調(diào)度命令的最安全方式之一。然而,不建議在 Xcode 11[4] 中使用 DispatchQueue。如果你在 Xcode 11 中使用 DispatchQueue 作為調(diào)度器,它必須是串行的,以遵守 Combine 的操作符的契約。

ImmediateScheduler

一個(gè) ImmediateScheduler用來立即執(zhí)行異步操作。

  1. import Combine 
  2.  
  3. let immediateScheduler = ImmediateScheduler.shared 
  4.  
  5.   let aNum = [1, 2, 3].publisher 
  6.         .receive(on: immediateScheduler) 
  7.         .sink(receiveValue: { 
  8.        print("Received \$0) on thread \(Threa.currentT")t 
  9. }) 

例如,上面的代碼塊將發(fā)送一個(gè)類似于下面的代碼塊的輸出。

  1. Received 1 on thread <NSThread: 0x400005c480>{number = 1, name = main} 
  2. Received 2 on thread <NSThread: 0x400005c480>{number = 1, name = main} 
  3. Received 3 on thread <NSThread: 0x400005c480>{number = 1, name = main} 

ImmediateScheduler 在應(yīng)用程序的當(dāng)前線程上立即執(zhí)行命令。上面的代碼塊是在主線程上運(yùn)行的。

RunLoop

RunLoop 調(diào)度器用于在一個(gè)特定的運(yùn)行循環(huán)上執(zhí)行任務(wù)。在運(yùn)行循環(huán)上的行動可能是不安全的,因?yàn)?RunLoops 不是線程安全的。因此,使用 DispatchQueue 是一個(gè)更好的選擇。

默認(rèn)的調(diào)度器

如果你沒有為一個(gè)任務(wù)指定調(diào)度器,Combine 會為它提供一個(gè)默認(rèn)的調(diào)度器。所提供的調(diào)度器將使用執(zhí)行該任務(wù)的同一線程。例如,如果你執(zhí)行一個(gè) UI 任務(wù),Combine 提供的調(diào)度器會在同一個(gè)UI線程上接收該任務(wù)。

切換調(diào)度器

在使用 Combine 的 iOS 開發(fā)中,許多消耗資源的任務(wù)都是在后臺完成的,以防止應(yīng)用程序的 UI 凍結(jié)或完全崩潰。然后,Combine 切換調(diào)度器,使任務(wù)的結(jié)果在主線程上執(zhí)行。

Combine使用兩種內(nèi)置方法來切換調(diào)度器:receive(on) 和 subscribe(on)。

receive(on)

receive(on) 方法用于在一個(gè)特定的調(diào)度器上發(fā)出數(shù)值。它為任何在它被聲明后的發(fā)布者改變一個(gè)調(diào)度器,如下面的代碼塊所示。

  1. Just(3) 
  2.    .map { _ in print(Thread.isMainThread) } 
  3.    .receive(on: DispatchQueue.global()) 
  4.    .map { print(Thread.isMainThread) } 
  5.    .sink { print(Thread.isMainThread) } 

上面的代碼塊將打印出以下結(jié)果。

  1. true  
  2. false  
  3. false  

subscribe(on)

subscribe(on) 方法被用來在一個(gè)特定的調(diào)度器上創(chuàng)建一個(gè)訂閱。

  1. import Combine  
  2. print("Current thread \(Thread.current)"
  3. let k = [a, b, c, d, e].publisher 
  4.     .subscribe(on: aQueue) 
  5.     .sick(receiveValue: { 
  6.         print(" got \($0) on thread \(Thread.current)"
  7.   }) 

上面的代碼塊將打印出以下結(jié)果。

  1. Current thread <NSThread: 0x400005c480>{number = 1, name = main} 
  2. Received a on thread <NSThread: 0x400005c480>{number = 7, name = null
  3. Received b on thread <NSThread: 0x400005c480>{number = 7, name = null
  4. Received c on thread <NSThread: 0x400005c480>{number = 7, name = null
  5. Received d on thread <NSThread: 0x400005c480>{number = 7, name = null
  6. Received e on thread <NSThread: 0x400005c480>{number = 7, name = null

在上面的代碼塊中,這些值是從不同的線程而不是主線程發(fā)出的。subscribe(on) 方法串行地執(zhí)行任務(wù),從執(zhí)行指令的順序可以看出。

用調(diào)度器執(zhí)行異步任務(wù)

在本節(jié)中,我們將學(xué)習(xí)如何在 subscribe(on) 和 receive(on) 調(diào)度器方法之間進(jìn)行切換。想象一下,一個(gè)發(fā)布者正在后臺運(yùn)行一個(gè)任務(wù)。

  1. struct BackgroundPublisher: Publisher 
  2.   typealias Output = Int 
  3.   typealias Failure = Never  
  4.  
  5.   func receive<K>(subscriber: K) where K : Subcriber, Failure == K.Failure, Output == K.Input { 
  6.   sleep(12)  
  7.   subscriber. receive(subscriptiton: Subscriptions.empty) 
  8.   _= subscriber.receive(3) 
  9.   subscriber.receive(completion: finished) 

如果我們從一個(gè)用戶界面線程中調(diào)用該任務(wù),我們的應(yīng)用程序?qū)鼋Y(jié) 12 秒。Combine 將在我們?nèi)蝿?wù)執(zhí)行的同一個(gè)調(diào)度器中添加一個(gè)默認(rèn)的調(diào)度器。

  1. BackgroundPublisher() 
  2.     .sink { _ in print("value received") } 
  3.  
  4. print("Hi!"

在上面的代碼塊中,Hi!,在接收到數(shù)值后,會在我們的控制臺中打印出來。我們可以看到下面的結(jié)果。

  1. value received 
  2. Hi! 

在 Combine 中,這種類型的異步工作經(jīng)常通過在后臺調(diào)度器上訂閱和在用戶界面調(diào)度器上接收事件來執(zhí)行。

  1. BackgroundPublisher() 
  2.     .subscribe(on: DispatchQueue.global()) 
  3.     .receive(on: DispatchQueue.main) 
  4.     .sink { _ in print("Value recieved") } 
  5.  
  6. print("Hi Again!"

上面的代碼片斷將打印出下面的結(jié)果。

  1. Hi Again! 
  2. Value received 

Hi Again! ,在接收到數(shù)值之前被打印出來。現(xiàn)在,發(fā)布者不會因?yàn)樽枞覀兊闹骶€程而凍結(jié)我們的應(yīng)用程序。

總結(jié)

在這篇文章中,我們回顧了什么是調(diào)度器以及它們?nèi)绾卧?iOS 應(yīng)用程序中工作。我們介紹了一些最佳的使用案例,包括 OperationQueue, DispatchQueue, ImmediateScheduler, 和 RunLoop 。我們還談到了 Combine 框架以及它是如何影響 Swift 中調(diào)度器的使用。

我們學(xué)習(xí)了如何在 Swift 中使用 receive(on) 和 subscribe(on) 方法來切換調(diào)度器。我們還學(xué)習(xí)了如何在 Combine 中使用調(diào)度器執(zhí)行異步功能,即在后臺調(diào)度器上訂閱并在用戶界面調(diào)度器上接收我們的值。

譯自 Understanding Swift schedulers[5]

參考資料

[1]調(diào)度器: https://developer.apple.com/documentation/combine/scheduler

[2]Combine: https://developer.apple.com/documentation/combine

[3]DispatchQueue: https://developer.apple.com/documentation/dispatch/dispatchqueue#:~:text=Dispatch%20queues%20are%20FIFO%20queues,tasks%20either%20serially%20or%20concurrently.&text=When%20you%20schedule%20a%20work%20item%20asynchronously%2C%20your%20code%20continues,the%20work%20item%20runs%20elsewhere.

[4]Xcode 11: https://forums.swift.org/t/runloop-main-or-dispatchqueue-main-when-using-combine-scheduler/26635/4

[5]Understanding Swift schedulers: https://blog.logrocket.com/understanding-swift-schedulers/

 

責(zé)任編輯:武曉燕 來源: Swift社區(qū)
相關(guān)推薦

2024-05-28 00:00:03

Java垃圾收集機(jī)制

2021-10-27 07:15:37

SpringAOP編程(

2022-05-07 07:43:07

Redis存儲系統(tǒng)數(shù)據(jù)庫

2021-11-29 07:24:08

ACID事務(wù)大數(shù)據(jù)

2021-07-14 08:00:12

Numa架構(gòu)Linux

2023-06-30 08:27:20

2023-06-09 08:06:14

操作系統(tǒng)調(diào)度器LLM

2017-11-15 08:50:59

數(shù)據(jù)庫MySQL執(zhí)

2010-04-01 13:58:16

WinCE 6.0Cashmere

2023-10-31 09:04:21

CPU調(diào)度Java

2024-01-15 08:41:25

SwiftTypeScrip語法

2022-07-20 08:55:10

編輯器VueTiptap

2020-07-23 07:51:51

Python編程語言工具

2023-03-29 08:13:48

MySQL檢索成本

2023-08-04 08:20:56

DockerfileDocker工具

2022-03-31 18:59:43

數(shù)據(jù)庫InnoDBMySQL

2022-05-24 08:21:16

數(shù)據(jù)安全API

2023-08-10 08:28:46

網(wǎng)絡(luò)編程通信

2023-09-10 21:42:31

2021-01-12 05:08:49

DHCP協(xié)議模型
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號