【Swift UI】Core Dataをマルチスレッドで扱う際の注意点!Managed Object Context

この記事からわかること
- Swift UIでCore Dataを利用する方法
- マルチスレッドでの使い方
- Managed Object Context(MOC)の役割と定義方法
- -com.apple.CoreData.ConcurrencyDebug 1とは?
- アプリがクラッシュ(EXC_BAD_ACCESS)する際の原因と解決方法
index
[open]
\ アプリをリリースしました /
環境
- Xcode:15.0.1
- iOS:17.0
- Swift:5.9
- macOS:Sonoma 14.1
Core Dataはスレッドセーフではない?
Core Dataでローカルにデータを保存する機能を利用する際にはコンテキスト(Managed Object Context)を使用します。このManaged Object Contextがスレッドセーフではないため、データの参照や追加などを扱う際に複数のスレッドやバックグラウンドスレッドから操作するとアプリがクラッシュする可能性があります。
解決方法としては「スレッドごとにManaged Object Contextを作成しスレッドごとのNSPersistentContainerを作成する」方法が公式で推奨されています。クラッシュを解決したいだけで、パフォーマンスに影響がなさそうならスレッドを統一するのも1つの手かもしれません。
バックグラウンド用のコンテキストはnewBackgroundContext
メソッドから取得できるようです。
private static var contextBackground: NSManagedObjectContext {
PersistenceController.shared.container.newBackgroundContext()
}
またperform
メソッドを使用してバックグラウンドスレッド上で処理を行わせることもできるようです。
let context = persistentContainer.viewContext
context.perform {
// バックグラウンドスレッドで実行される処理
}
スレッドセーフとは?
スレッドセーフとはマルチスレッドが有効でな実行環境で、特定の処理を複数のスレッドで並行して実行しても、問題が生じない仕様や設計になっていることを指します。SwiftではGCD(Grand Central Dispatch)と呼ばれるマルチスレッド処理を行うための機能が提供されています。
マルチスレッドになっていないかチェックする方法
Core Dataを導入しているプロジェクトでマルチスレッドでコンテキストが利用されているかをチェックするためにはXcodeのスキームの引数に-com.apple.CoreData.ConcurrencyDebug 1
を追加して有効にした状態でビルドします。

アプリを操作すると異なるスレッドでContextが参照された際にEXC_BREAKPOINT
などのエラーが発生して教えてくれるようになりました。
マルチスレッドで実行すると発生するエラー
マルチスレッドでコンテキストが利用されている場合に必ずエラーが発生するわけではないようで、正常に動作する場合やアプリがクラッシュする場合など状況に応じて変化するようです。
クラッシュはしないがXcodeのログに以下のようなエラーが表示されたり
CoreData: error: NULL _cd_rawData but the object is not being turned into a fault
以下のエラーが発生しアプリがクラッシュすることもありました。
EXC_BAD_ACCESS (code=1, address=0xb91088020)
ご覧いただきありがとうございました。
個人開発に限界を感じたらiOSに特化したプログラミングスクール「iOSアカデミア」も検討してみてください!無料相談可能で「最短・最速」でiOSエンジニアになれるように手助けしてくれます。