苦等半年的 Swift Playgrounds 4.0 終於發佈,新版更新了非常多功能,特別是在非同步(async)的相關指令,非同步模式是網路程式、GUI互動、並行運算的基礎,而並行運算又是大數據、人工智慧、3D繪圖等高速運算所必須,因此顯得特別重要,而且新語法能簡化程式碼的撰寫,本單元後半部分(第6~10課)會盡量採用新的指令語法,須配合使用 Swift Playgrounds 4.0。
下載 Swift Playgrounds 4.0 之前,記得要將作業系統升級到 iPadOS 15.2 或 macOS 12.1,Swift Playgrounds下載入口: https://www.apple.com/tw/swift/playgrounds/
在第2課我們學習從網路抓圖,範例3-2a是一個非常基本的網路抓圖程式:
// 3-2a 讀取網路圖片(URLSession)
// Created by Heman, 2021/09/02
import PlaygroundSupport
import SwiftUI
let 網址 = "<https://picsum.photos/720/1280>"
struct 抓圖: View {
@State var 下載圖片: UIImage?
var body: some View {
if 下載圖片 == nil {
ProgressView()
.onAppear {
guard let myURL = URL(string: 網址) else { return }
URLSession.shared.dataTask(with: myURL) { 回傳資料, 回應碼, 錯誤碼 in
if let 圖檔 = UIImage(data: 回傳資料!) {
print(回應碼 ?? "No response")
下載圖片 = 圖檔
} else {
print(錯誤碼 ?? "No error")
}
}.resume()
}
} else {
Image(uiImage: 下載圖片!)
.resizable()
.scaledToFit()
}
}
}
PlaygroundPage.current.setLiveView(抓圖())
原來的抓圖程式,主要是用 URLSession.shared.dataTask() 這個通用物件,大部分網路程式都可以用它來寫,是本單元前半部(第1課到第5課)的核心物件。
Swift Playgrounds 4.0 增加了一個 AsyncImage 物件,讓我們寫程式下載網路圖片變得更容易,將上面範例3-2a改用 AsyncImage 後,程式簡化如下,減少了將近一半的程式碼,不可思議吧:
// 3-6a 讀取網路圖片(AsyncImage)
// Modified (based on 3-2a) by Heman, 2021/12/16
import PlaygroundSupport
import SwiftUI
let 網址 = "<https://picsum.photos/720/1280>"
struct 抓圖: View {
var body: some View {
AsyncImage(url: URL(string: 網址)) { 下載圖片 in
下載圖片
.resizable()
.scaledToFit()
} placeholder: {
ProgressView()
}
}
}
PlaygroundPage.current.setLiveView(抓圖())
AsyncImage 也是一個 View 物件類型,跟其他 SwiftUI 的 View 物件語法類似,所以用起來很方便。物件的初始化需要一個 URL 物件實例當作參數,下載取得的圖片會傳入後面接的匿名函式,在取得下載圖片之前,可指定另一個 View 當作緩衝(在此為 ProgressView()),這個緩衝的參數稱為 placeholder,就是臨時用來佔位置的東西(圖片或視圖)。
因為 AsyncImage 是非同步的運作模式,所以運作過程跟原來範例 3-2a 完全相同,會先顯示 ProgressView() 視圖,當下載完成(取得 Response)後,才會進入後接的匿名函式,顯示已下載的圖片。
注意原來3-2a裡用來更新畫面的狀態變數(@State var)已不需要,表示 AsyncImage 能自己掌握狀態更新畫面。
執行結果如下: