async、awaitを使いたい
Swiftのasync、awaitを使ってコードを書いていると、
既存のプロジェクトのコードや、ライブラリなど、クロージャ・コールバック(コンプレーションハンドラー)の形で書いているコードを呼び出す場合があります。
その時に、そのままクロージャ・コールバック(コンプレーションハンドラー)の形でコードを書いても良いのですが、async、awaitの形で統一して書きたいです。
書きたいですよね??(;・∀・)
ただ、少しのコードであれば書き直すのですが、量が多かったり、書き直す事ができない場合があります。
その時にクロージャ・コールバック(コンプレーションハンドラー)のメソッドをラップして、書き換えずにasync、awaitに対応する方法。
コードはシンプルに最低限の事しか書いてませんので、処理内容に応じて記述が必要です。
※ネットで調べていると、iOS14でバグがあったとかの記述を見かけました。
個人的には問題に遭遇していないのですが、問題があるのかも・・・?しれないので、使われる時は注意が必要かもしれないです。
※個人的には今の2022年8月時点でiOS14を正式にサポートしなくても良いのでは・・・と思ったりしますが、どうなんでしょう・・・(´ε`;)
ラップする前の(今までクロージャ・コールバック(コンプレーションハンドラー)での)コード
func sessionRequest(urlText: String, completion: @escaping (Result<Data?, Error>) -> Void){
if let url = URL(string: urlText) {
let session = URLSession.shared.dataTask(with: url) { data, res, error in
if let error = error {
// 失敗した時の処理
completion(.failure(error))
} else {
// 成功した時の処理
completion(.success(data))
}
}
session.resume()
} else {
completion(.failure(TestError.invalid("invalid url")))
}
}
enum TestError: Error {
case invalid(String)
}
このような形でクロージャ・コールバック(コンプレーションハンドラー)の形で書いているメソッドがあるとします。
これくらいであれば、書き直す事もできますが、内容が複雑だったりしたら、触りたくないです。
そのため、ラップして中身を変えずに対応したい。
async、awaitに対応するためのコード
func sessinRequestAsync(urlText: String) async throws -> Data? {
do {
guard let url = URL(string: urlText) else {
throw TestError.invalid("invalid url")
}
return try await withCheckedThrowingContinuation({ contiuation in
let session = URLSession.shared.dataTask(with: url) { data, res, error in
if let error = error {
contiuation.resume(throwing: error)
} else {
contiuation.resume(returning: data)
}
}
session.resume()
})
} catch {
throw error
}
}
このように、withCheckedThrowingContinuationで囲う事で、async、awaitに対応したコードに変化させる事ができます。
めっちゃ簡単ですよね・・・
withCheckedThrowingContinuationメソッドはエラーをスローする場合があるらしいので、tryを付けて呼び出す必要があります。
withCheckedThrowingContinuationメソッドはエラーをスローする場合がある処理に利用し、
withCheckedContinuationはメソッドはエラーをスローしない場合に利用するようです。
Apple Developerサイト Updating an App to Use Swift Concurrency
https://developer.apple.com/documentation/swift/updating_an_app_to_use_swift_concurrency
詳しくはアップルのDeveloperサイトなどを見て頂くのがわかりやすいです。
※アップルは本当によくDeveloperサイトの見た目を更新されますよね。
以上が既存のプロジェクトのコードをasync、awaitに対応させるための、シンプルなコードです。
コメント