Core Spotlightの実装を終えたタイミングで、以前から気になっていたSwift 6のStrict Concurrencyモードへの移行に挑戦しました。
1. 設定を1つ変えるだけの軽い作業だと思っていた
最初、Xcodeの言語バージョン設定を「Swift 6」に切り替えるだけの、比較的軽い作業だと思い込んでいました。
切り替え後のビルド結果:
大量の警告・エラーが一斉に発生
実際に切り替えてみると、これまで見逃されていたデータ競合の可能性がある箇所すべてに警告やエラーが出るようになり、想定していたよりもはるかに大きな作業になりました。既存のコード量が多いほど、この移行は一気にではなく段階的に進める必要があると気づきました。
2. Sendableプロトコルの意味を誤解していた
Sendableに準拠させろというエラーが大量に出たのですが、最初はとりあえずプロトコルを付ければエラーが消えるおまじないのようなものだと考えていました。
struct RecordSnapshot: Sendable {
let title: String
}
実際には「複数のスレッドから安全にやり取りできるデータかどうか」を表す印であり、内部に可変のクラスや安全でない参照を持ったままSendableを付けても本質的な解決にはなりません。中身が本当にスレッドセーフな構造になっているかを一つずつ見直す必要があると分かりました。
3. 古いUIKitベースのコードとの相性で詰まった
一部の画面でまだ使っていたUIKitベースの古いコードが、@MainActorが前提のSwiftUI側のコードとかみ合わず、ビルドエラーが解消できませんでした。
発生したエラー:
Main actor-isolated property を非isolatedなコンテキストから参照
UIKit側のデリゲートメソッドに明示的に@MainActorを付けたり、間に非同期処理を挟む形に書き換えたりすることで一つずつ解消しましたが、UIKitとSwift Concurrencyの世代差を意識しながらの地道な修正作業になりました。
4. 一気に全部直そうとして収拾がつかなくなった
最初は勢いでアプリ全体を一度にStrict Concurrency対応させようとしたのですが、警告の数が多すぎて、どこまで直したか分からなくなってしまいました。
方針転換後の進め方:
ファイル単位でTargeted設定にし、1ファイルずつ完全対応してから次へ
Xcodeのビルド設定で「対象を絞ったモード」に切り替え、モジュールやファイル単位で段階的に完全対応させていく方針に変更したことで、進捗を見失わずに済むようになりました。大きな移行作業ほど、一気にやらず区切りを付けて進めることの大切さを実感しました。
まとめ
- Swift 6への切り替えは設定変更ひとつでは終わらず、既存コード量に応じた地道な対応が必要になる
Sendableはエラー消しのおまじないではなく、本当にスレッドセーフかどうかを見直すきっかけにする- UIKitベースの古いコードとは
@MainActorまわりで衝突しやすく、世代差を意識した個別対応が必要 - 一気に全体対応しようとせず、ファイルやモジュール単位で段階的に進めると収拾がつきやすい
警告を消すだけの作業に見えて、実際はアプリ全体の非同期処理設計を見直す機会になった移行でした。
本記事は生成AI(Claude)を活用して執筆・編集しています。内容は実体験に基づき、執筆者本人が確認・監修しています。


コメント