<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          o1?/???? WWDC | 圖解 Swift async/await

          共 3993字,需瀏覽 8分鐘

           ·

          2021-06-27 05:43



          Swift 開發(fā)者終于在 WWDC21 中盼來了 async/await。作為現(xiàn)代編程語言的標志之一,async/await 可以讓我們像編寫常規(guī)代碼一樣,輕松地編寫異步代碼,這樣能更直觀且更安全地表達我們的思路。同時,async/await 是整個 Swift 結(jié)構(gòu)化并發(fā)的基礎(chǔ),所以我們從這個 Session 開始,一起來探索 Swift 新的并發(fā)框架。


          加載縮略圖步驟



          這個 Session 通過加載縮略圖片為我們演示了 async/await 的使用。加載縮略圖片分為以下幾個步驟:

          ? 從 URL 字符串創(chuàng)建一個 URLRequest 對象;
          ? URLSession 的 dataTask(with:completion:) 方法獲取要請求圖片數(shù)據(jù);
          ? UIImage(data:) 從圖片數(shù)據(jù)中創(chuàng)建一個圖像;
          ? UIImage 的 prepareThumbnail 方法從原始圖像中渲染一個縮略圖

          這些操作的每一步都依賴于前一個步驟的結(jié)果,所以必須按順序執(zhí)行。在這四步操作中,第二步和第四步會比較費時,所以這兩步操作一般通過異步調(diào)用來完成。


          原始版本代碼


          原始的調(diào)用方式如上代碼所示,這里定義了一個 fetchThumbnail 函數(shù),其中有一個 completion 參數(shù),用于將輸出返回給調(diào)用者。

          fetchThumbnail 函數(shù)體中規(guī)中舉地按以上步驟來完成任務

          ? 調(diào)用 thumbnailURLRequest,該操作是同步的;
          ? 調(diào)用 URLSession 的 dataTask(with:completion:),這是個異步操作,需要調(diào)用 resume() 方法啟動異步工作;fetchThumbnail 返回執(zhí)行其它任務
          ? 在 dataTask(with:completion:) 的完成處理程序中,處理獲取數(shù)據(jù)后的操作;
          ? 正常獲取數(shù)據(jù)的情況下,通過 UIImage(data:) 來創(chuàng)建一個圖像,這個操作是同步的;
          ? 調(diào)用 UIImage 對象的 prepareThumbnail 方法生成縮略圖,該方法也是個異步方法;

          這里有兩個明顯的問題:

          ? 必須時刻注意在哪里需要調(diào)用 completion(這里就有 5 處),如果忘記調(diào)用 completion 來通知調(diào)用者失敗(Swift 不能保證強制執(zhí)行 completion),則可能導致流程異常;
          ? 這里大約 20 行的代碼,看似是按流程來走,但層層嵌套會讓代碼顯示更加晦澀(所謂的回調(diào)地獄);

          有一些現(xiàn)成的改進方案,但效果并不理想:

          ? completion 的入?yún)⒖梢允褂脴藴蕩斓?Result,會更安全一點,但也只是一點點;
          ? 類 future 方法,但代碼沒有更簡潔和安全

          現(xiàn)在,必須祭出 async/await 了。


          async/await 版本代碼

          async/await 版本代碼如上所示。

          函數(shù)簽名有幾處明顯的變化:

          ? 入?yún)⒉辉俚?completion 處理程序;
          ? 返回值是 UIImage 類型,表示函數(shù)返回的縮略圖,同時通過關(guān)鍵字 throws 標識可以拋出一個異常;
          ? 在 throws 前面添加了關(guān)鍵字 async,表明這是一個異步函數(shù)(注意:如果沒有 throws 關(guān)鍵字,則 async 直接放在 -> 前面)

          fetchThumbnail 的實現(xiàn)更加簡潔明了:

          ? 調(diào)用依然從 thumbnailURLRequest 開始,該操作是同步的,阻塞線程;
          ? 調(diào)用 URLSession 的 data(for:) 開始下載數(shù)據(jù),這里有幾個變化

             ? 使用 await 標記方法調(diào)用,表明這是一個異步操作;如果一個表達式里面有多個異步函數(shù)調(diào)用,則只需要寫一次 await
          ? data(for: ) 方法是可等待的,調(diào)用后,會掛起自己,解除線程阻塞;
          ? 使用 try 是因為 fetchThumbnail 被標記為 throws,如果網(wǎng)絡(luò)請求有異步,則直接拋出異常;
          ? data(for:) 完成后,恢復 fetchThumbnail,并將返回的數(shù)據(jù)及請求響應賦值給 data 和 response,就像普通的賦值操作一樣;

          ? 判斷響應是否有效,如果響應碼不為 200,則拋出異步,這一步為同步操作;
          ? 正常獲取數(shù)據(jù)后,通過 UIImage(data:) 來創(chuàng)建一個圖像,這個操作是同步的;
          ? 調(diào)用 UIImage 對象的 thumbnail 屬性生成縮略圖,這是個可等待的屬性(此處為非 SDK 內(nèi)置的屬性,而是自定義的屬性),這里同樣使用 await 來標識異步操作;如果 thumbnail 失敗,則拋出一個異常;

          我們可以看到,短短的 6 行代碼就實現(xiàn)了上面大約 20 行代碼的功能,優(yōu)點顯而易見:

          ? 更安全:整個過程能確保出錯時拋出異常;
          ? 更簡潔:避免的代碼的層層嵌套;
          ? 更能體現(xiàn)意圖:整個代碼基本是和我們預定的流程保持了一致;


          可等待屬性


          如上代碼,是上面使用的 thumbnail 屬性的實現(xiàn)。它是 UIImage 的一個擴展屬性。

          這里需要注意幾點:

          ? 異步屬性必須是只讀的,可寫屬性不能聲明為異步屬性;
          ? 異步屬性需要有一個明確的 getter,async 關(guān)鍵字位于 get 后;
          ? 從 Swift 5.5 開始,getter 也可以拋出異常,如果同時是異步的,則 async 關(guān)鍵字位于 throws 前面;
          ? await 可用于屬性 body 中的表達式,以表明操作的異步性;


          調(diào)用流程對比


          普通函數(shù)的調(diào)用流程如上圖所示:

          ? 調(diào)用函數(shù);
          ? 函數(shù)獲取線程的控制權(quán),并完全占用該線程;
          ? 函數(shù)執(zhí)行完成返回或者拋出錯誤,將控制權(quán)交還調(diào)用方

          這里普通函數(shù)放棄線程控制權(quán)的唯一方式就是執(zhí)行完成


          而異步函數(shù)的調(diào)用流程則如上圖所示:

          ? 調(diào)用函數(shù);
          ? 函數(shù)獲得線程控制權(quán);
          ? 函數(shù)運行后,掛起,同時放棄對線程的控制,并將控制權(quán)交給系統(tǒng),系統(tǒng)可自由支配該線程;
          ? 系統(tǒng)確定何時恢復函數(shù);
          ? 函數(shù)恢復后重新獲得控制權(quán),并繼續(xù)工作;
          ? 函數(shù)執(zhí)行完成或拋出異常后,返回調(diào)用方,將控制權(quán)交還給調(diào)用方

          這里需要注意幾點:

          ? 一個異步函數(shù)掛起時,也會掛起它的調(diào)用者,所以調(diào)用者也必須是異步的;
          ? 異步函數(shù)可以多次掛起,就像上面的 fetchThumbnail 方法一樣使用了兩個 await 關(guān)鍵字;
          ? 異步函數(shù)掛起時,不會阻塞線程;
          ? 異步函數(shù)可能會在一個完全不同的線程上恢復;
          ? async 函數(shù)并不一定會掛起;


          單元測試


          以往,我們想要對網(wǎng)絡(luò)請求任務做一些單元測試時,需要借助 XCTestExpectation 這個類。


          而有了 async/await 后,異步函數(shù)的單元測試更加簡單了。


          異步任務


          我們上面提到,異步函數(shù)的調(diào)用者也需要是異步函數(shù)。但有些情況下,確實需要在同步方法中調(diào)用異步函數(shù),這時就需要用到異步任務功能了。

          即如上代碼,通過 async 閉包將任務打包,以執(zhí)行異步操作。


          代碼遷移

          對于老代碼,我們更關(guān)注的是如何更好地使用上新特性。對于 async/await,Swift 團隊也為我們做了很多準備:


          ? 提供了大量的異步 API,以替代采用完成處理程序的 API

          ? 許多委托方法也有相應的異步替代方法


          Continuation 模式

          Swift 是如何與系統(tǒng)協(xié)作,完成異步代碼的恢復呢。答案就是 Continuation 模式,方法的調(diào)用者等待函數(shù)調(diào)用的結(jié)果并提供一個閉包來指定下一步要做什么。當函數(shù)調(diào)用完成時,調(diào)用完成處理程序恢復調(diào)用者想要對結(jié)果執(zhí)行的操作。這種協(xié)同執(zhí)行正是 Swift 中異步函數(shù)的工作方式。

          為此,Swift 提供了 withCheckedThrowingContinuation 函數(shù)

          Suspends the current task, then calls the given closure with a checked throwing continuation for the current task.

          以及 CheckedContinuation 結(jié)構(gòu)體

          A mechanism to interface between synchronous and asynchronous code, logging correctness violations.

          通過這些結(jié)構(gòu)體和函數(shù),調(diào)用方可以訪問可用于恢復掛起的異步函數(shù)的延續(xù)值。CheckedContinuation 結(jié)構(gòu)體還提供了多個 resume 方法,用來回傳結(jié)果值。

          Continuation 提供了一種強大的方式來手動控制異步函數(shù)的執(zhí)行,不過有一點需要記住:

          resume 在每個代碼分支上必須且只能調(diào)用一次

          如果某個分支沒有調(diào)用 resume,異步調(diào)用將永遠掛起;而如果某個分支調(diào)用了多次,則可能會破壞程序數(shù)據(jù)。這兩種情況 Swift 都會給出警告或錯誤。


          小結(jié)

          以上就是對《Meet async/await in Swift》的整理,展示了 async/await 的使用及運行機制,歡迎來到 Swift 新世界。



          推薦閱讀

          ?  oo?/???? WWDC | 初識 Xcode Cloud
          ?  oo?/???? WWDC | 性能優(yōu)化終極生存指南
          ?  o1o/???? WWDC | 8 分鐘優(yōu)化你的 App Store 產(chǎn)品頁
          ?  o11/???? WWDC | App Clips 新特性


          分享,收藏,點贊,在看四連,就差您了 ??????

          瀏覽 122
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产免费一区 | 亚洲综合娱乐网 | 手机av在线观看 台湾成人在线视频 | 黄色片成年人免费的 | 北条麻妃被两个黑人玩 |