Swift で Future や Promise にあたるものを使いたくなった時に、毎回ググり直すので自分用のメモです。
わかりやすく **「古い」「新しい」**と書いていますが単純に登場した順番であって、良し悪しの話ではないです。
古い関数をラップする
- こういう古い書き方の関数があり、都合によってこれ自体を書き換えれられない場合
Old.swift
func old(completion: @escaping () -> Void) {
print("処理中...")
completion()
}
- 新しくこういう風にラップしましょう
New.swift
func new() async {
try! await withCheckedThrowingContinuation { continuation in
old {
continuation.resume()
}
}
}
withCheckedThrowingContinuation
の中で古い関数を呼ぶことがポイントです
上記の例ではエラーが起こらない前提があるので try!
を使っています
ラップした関数を呼び出す
- すると今までと比べて綺麗に呼び出せるようになります。
OldAndNew.swift
// 今まで通り old を呼び出す方法
print("処理前")
old {
print("処理後")
}
/*
処理前
処理中
処理後
*/
// 新しくラップしなおした new を呼び出す方法
print("処理前")
await new()
print("処理後")
/*
処理前
処理中
処理後
*/
おまけ
- ちなみに SwiftUI の Button のように非同期のアクションに対応していない箇所から呼びたい場合は Task の中で使います。
SwiftUIButton.swift
...
Task {
print("処理前")
await new()
print("処理後")
}
...
- コールバックで値を返す場合やエラーハンドリングに応じて
.resume(returning:)
や.resume(throwing:)
,.resume(with:)
といった関数も用意されています。
詳しくは withCheckedThrowingContinuation でググりましょう。(結局ググるんかい)
これでようやくSwiftでもコールバック地獄から抜け出せる。やったぜ✌️