iT邦幫忙

0

iOS SDK 學習筆記02:async / await

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20230405/20158406nd257ZrYEs.jpg


在閱讀 Apple Education 出版的 Develop in Swift Data Collections 這本書時,關於 URLSession 部分,注意到在 Swift 5.5 之後引入新的 async / await API,因此想簡單做個筆記。而本文主要目的是比較新舊不同的實作方式,對於錯誤處理就先簡單處理。如果有理解錯誤,還煩請指正,謝謝。內容主要改編書中提到的例子。

  • 先定義取得的資料 Struct
enum PhotoInfoError: Error, LocalizedError {
    case itemNotFound
}

struct PhotoInfo: Codable {
    var title: String
    var description: String
    var url: URL
    var copyright: String?

    enum CodingKeys: String, CodingKey {
        case title
        case description = "explanation"
        case url
        case copyright
    }
}
  • 使用 async / await
func fetchPhotoInfoNew() async throws -> PhotoInfo {
    let url = URL(string: "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY")!
    let session = URLSession(configuration: .default)
    let (data, response) = try await session.data(from: url)

    guard let httpResponse = response as? HTTPURLResponse,
          httpResponse.statusCode == 200 else {
        throw PhotoInfoError.itemNotFound
    }
    let jsonDecoder = JSONDecoder()
    let photoInfo = try jsonDecoder.decode(PhotoInfo.self, from: data)
    return(photoInfo)
}

Task {
    do {
        let photoInfo = try await fetchPhotoInfoNew()
        print("Successfully fetched PhotoInfo: \(photoInfo)")
    } catch {
        print("Fetch PhotoInfo failed with error: \(error)")
    }
}

用 async 關鍵字宣告 fetchPhotoInfoNew() 為非同步函式,並使用 await 關鍵字執行 URLSession 的 data(from:) 方法獲取 URL 的回應。當回應的 HTTP 狀態碼為 200 時,會將數據解碼為 PhotoInfo 並返回該實例。Task 這個實例則用於執行非同步函數 fetchPhotoInfoNew(),印出 photoInfo 的值或處理錯誤。

而在這之前的作法為使用 URLSession.dataTask(with: URLRequest, completionHandler: (Data?, URLResponse?, Error?) -> Void) { ... }

當 data task 完成時,在 completionHandler 這個 closure 裡處理 response、data,或者 error 的狀況。也就是說,這個 closure 是當 task 完成時會被自動呼叫,並透過這個 closure 回傳結果,以便開發者進一步處理。程式碼如下:

  • 使用 URLSession.dataTask
func fetchPhotoInfoOld() {
    if let url = URL(string: "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY") {
        let session = URLSession(configuration: .default)
        let task = session.dataTask(with: url) { data, response, error in
            guard let httpResponse = response as? HTTPURLResponse,
                  httpResponse.statusCode == 200 else {
                return
            }
            guard let safeData = data else {
                print("No data")
                return
            }
            do {
                let jsonDecoder = JSONDecoder()
                let photoInfo = try jsonDecoder.decode(PhotoInfo.self, from: safeData)
                print("Successfully fetched PhotoInfo: \(photoInfo)")
            } catch {
                print("Failed to decode PhotoInfo: \(error)")
            }
        }
        task.resume()
    }
    
}
fetchPhotoInfoOld()

使用 async / await 的好處是避免使用那一串 closure,讓程式碼變得較為簡潔。


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言