証明書エラーを解決してひと息ついたところで、以前からcompletionHandler(完了時に呼ばれる関数)だらけで読みにくくなっていた通信処理を、Swiftのasync/awaitに書き換えてみることにしました。「読みやすくなるはず」という期待とは裏腹に、書き換えの途中で何度もつまずきました。
1. UI更新の箇所でアプリが突然クラッシュした
まずは一番単純な通信処理をasync/awaitに書き換えたところ、画面のラベルを更新する箇所で謎のクラッシュが発生しました。
Task {
let data = try await fetchData()
label.text = data.title // ここでクラッシュすることがある
}
原因は、通信処理は自動的にバックグラウンドのスレッドで実行され得るのに対し、UIの更新はメインスレッドで行わなければならないというルールを意識できていなかったことでした。completionHandlerの時代はDispatchQueue.main.asyncを書く習慣があったのに、async/awaitに変えた途端にその意識が抜け落ちていました。
2. @MainActorの意味を理解せずになんとなく付けていた
クラッシュを直そうと検索して見つけた@MainActorという属性を、意味も分からずおまじないのように関数につけて解決したつもりになっていました。
@MainActor
func updateLabel(with data: Data) {
label.text = data.title
}
後から調べて、@MainActorは「この関数(またはクラス全体)は必ずメインスレッドで実行する」とコンパイラに約束させる仕組みだと理解しました。なんとなく付けて動いたから良し、ではなく、なぜそれが必要なのかを理解してから使うべきだったと反省しました。
3. Taskを毎回作っていて画面遷移後もクラッシュした
一覧画面から詳細画面に素早く遷移すると、遷移前の画面で開始したTaskの処理が生きたままで、存在しない画面の要素を更新しようとしてクラッシュすることがありました。
private var loadTask: Task<Void, Never>?
func loadData() {
loadTask?.cancel() // 前のTaskをキャンセルしてから
loadTask = Task {
let data = try await fetchData()
// ...
}
}
Taskは明示的にキャンセルしない限り動き続けるという性質を理解しておらず、画面が閉じられたら処理も自動的に止まるだろうと思い込んでいました。Taskをプロパティとして保持し、新しい処理を始める前に前のものをキャンセルする、という一手間が必要だと学びました。
4. 古いcompletionHandler方式のコードと混在して余計に読みにくくなった
一気に全部書き換える時間がなく、一部の関数だけasync/awaitに変え、呼び出し元は従来のcompletionHandlerのまま、という中途半端な状態を長く放置してしまいました。
// 呼び出し元がcompletionHandler方式のまま残っていると、
// Task { } で無理やりブリッジすることになり、かえって読みにくい
func oldStyleFetch(completion: @escaping (Data) -> Void) {
Task {
let data = try await fetchData()
completion(data)
}
}
「新しい書き方の方が読みやすいはず」と思って始めた書き換えが、中途半端な混在状態では逆に複雑になることに気づきました。書き換えるなら、呼び出し元も含めて一つの機能単位でまとめて完了させる方が結果的に早いと実感しました。
まとめ
- async/awaitでもUI更新はメインスレッドで行う必要があり、
@MainActorはその約束を仕組みとして保証してくれる @MainActorはおまじないではなく、意味を理解した上で使うTaskは明示的にキャンセルしない限り動き続ける。画面が閉じられても処理が生きたままになることがある- completionHandlerとasync/awaitを中途半端に混在させると、かえって読みにくくなる。書き換えるなら呼び出し元も含めて一気に終わらせる
見た目のコード量が減って読みやすくなる一方で、スレッドやライフサイクルへの理解が浅いまま書き換えると、新しい種類のバグを生むこともあると学んだ機会でした。
次は、アプリのレビュー・評価を増やすためにやったことをまとめます。
本記事は生成AI(Claude)を活用して執筆・編集しています。内容は実体験に基づき、執筆者本人が確認・監修しています。


コメント