Core Data — 主要な概念、NSManagedObject、アーキテクチャ

著者: IT Sectr 公開日: 2026-03-11 読了時間: 11 分

Core Dataは、iOSおよびmacOSアプリケーションでオブジェクトグラフを管理するためのAppleのフレームワークです。データの永続化、変更追跡、操作の元に戻す、NSFetchedResultsControllerによるUI統合を提供します。Apple Developerのドキュメント(2025年)によると、Core Dataはデータベースではなく、デフォルトでSQLiteを永続ストアとして使用するオブジェクトモデリング層です。

重要なポイント

  • Core DataはiOS/macOS向けのORMフレームワークで、オブジェクトグラフを管理しストアに永続化します。
  • NSManagedObjectModelはCore Dataモデルのエンティティ、属性、リレーションシップを記述するデータスキーマです。
  • NSManagedObjectContextは変更追跡機能付きでオブジェクトを作成、読み取り、更新、削除するためのワークスペースです。
  • NSPersistentContainerはiOS 10以上でモデル、コンテキスト、ストアをカプセル化する統一されたエントリポイントです。
  • NSFetchedResultsControllerはCore DataをUITableView/UICollectionViewと統合し、変更時に自動更新します。

Core Dataとは?

Core Dataは、AppleのCocoa Touch SDKの一部であるオブジェクトグラフ管理および永続化フレームワークです。データを扱うためのオブジェクト指向インターフェースを提供します。開発者はエンティティ、属性、リレーションシップを操作し、Core Dataはこれらのオブジェクトを内部でリレーショナルデータベースのレコードに変換します。

Core DataはMac OS X 10.4 Tiger(2005年)でmacOS向けに導入され、iOS 3.0(2009年)に移植されました。20年以上の間に、フレームワークはSQLite上の単純な抽象化層から、NSPersistentCloudKitContainerによるクラウド同期、自動コンテキスト管理によるマルチスレッド、Swift Concurrencyによる非同期ロードを備えた本格的なスタックへと進化しました。

Slack Community(2025年)のiOS開発者調査によると、Core Dataは商用iOSアプリケーションの68%でローカルデータストレージに使用されています。複雑さと階層化アーキテクチャに対する批判にもかかわらず、システムとの緊密な統合、ゼロコスト(SDKに内蔵)、iCloud同期サポートにより、Appleアプリケーションの標準であり続けています。

Core Dataはデータベースではない

よくある誤解はCore Dataをデータベースと考えることです。このフレームワークは直接SQLクエリを実行せず、DBMSではありません。Core Dataは永続化にSQLite、Binary、またはIn-Memoryストアを使用できるオブジェクトグラフ管理層です。类比:Core DataはAppleエコシステム向けのHibernateやEntity Frameworkのようなもので、その下のSQLiteはHibernateの下のMySQLのようなものです。

Core Dataのアーキテクチャ:スタックとコンポーネント

Core Dataスタックは、NSManagedObjectModel(データスキーマ)、NSPersistentStoreCoordinator(ストアコーディネーター)、NSManagedObjectContext(作業コンテキスト)、NSPersistentContainer(iOS 10以降これら3つを統合する統一コンテナー)の4つの相互接続されたコンポーネントで構成されています。NSPersistentContainerはスタックの作成と構成を自動化します。

各コンポーネントは厳密に定義された機能を実行します。NSManagedObjectModelはエンティティ記述を含む.xcdatamodeldファイルをロードします。NSPersistentStoreCoordinatorはモデルを物理ストアファイル(SQLite)に接続します。NSManagedObjectContextはオブジェクトを操作するための一時的な領域を提供します。コンテナーはすべてを単一の初期化呼び出しに統合します。

Core Dataのストアタイプ

SQLite(NSSQLiteStoreType)はほとんどのアプリケーションで使用される標準ストアです。データはACIDトランザクションをサポートする単一の.sqliteファイルに保存されます。Binary(NSBinaryStoreType)は小規模データセット(最大数百オブジェクト)用のバイナリ形式ストアです。In-Memory(NSInMemoryStoreType)はディスク永続化なしのRAM上の一時ストアで、テストやキャッシングに使用されます。

ストアタイプ形式パフォーマンス使用タイミング
SQLite.sqlite高い本番環境の標準選択
Binary.binary中程度小規模データセット
In-MemoryRAM最大テスト、キャッシュ、一時データ
CloudKitiCloudネットワーク依存デバイス間同期

ストアタイプはNSPersistentStoreDescriptionの初期化時に1行で設定されます。開発者はオブジェクト操作コードを変更することなく、ユニットテスト用にSQLiteからIn-Memoryへ、またはiCloud同期用にCloudKitへ切り替えることができます。Core Dataは統一されたコンテキストAPIを通じてストアタイプ間の違いを抽象化します。

NSManagedObjectとNSManagedObjectContext

NSManagedObjectはすべてのCore Dataオブジェクトの基底クラスで、単一のエンティティレコードを表します。各管理対象オブジェクトは一意のNSManagedObjectID(永続識別子)を持ち、コンテキストに結び付けられ、KVO(キー値監視)を介して変更を追跡します。開発者はNSManagedObjectのサブクラスを作成して、型付けされたエンティティプロパティを定義します。

NSManagedObjectContextはCore Dataの中心的なコンポーネントで、すべてのオブジェクト操作のためのワークスペースを提供します。コンテキストは追加、削除、変更を追跡し(変更追跡)、undoManagerによる操作の元に戻しをサポートし、保存通知を受信すると他のコンテキストからの変更を自動的にマージします。

コンテキストのスレッドセーフティ

プライベートキューのルール:NSManagedObjectContextは.privateQueueConcurrencyTypeまたは.mainQueueConcurrencyTypeで作成されます。メインコンテキストはメインUIスレッドに結び付けられ、プライベートコンテキストはバックグラウンドキューで実行されます。各コンテキストは自分のキューでのみ使用する必要があります。別のスレッドから管理対象オブジェクトにアクセスするとクラッシュを引き起こします。parentContextを使用すると、非同期書き込みのためにコンテキストの階層を編成できます。

swift
struct CoreDataStack {
    let container: NSPersistentContainer

    init(name: String) {
        container = NSPersistentContainer(name: name)
        container.loadPersistentStores { _, error in
            if let error = error {
                fatalError("Failed to load store: \(error)")
            }
        }
        container.viewContext.automaticallyMergesChangesFromParent = true
    }

    func backgroundContext() -> NSManagedObjectContext {
        let context = container.newBackgroundContext()
        context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        return context
    }
}

NSPersistentContainerは自動的にviewContext(メインキュー)を作成し、バックグラウンド操作用にnewBackgroundContext()を提供します。automaticallyMergesChangesFromParent = trueを設定すると、viewContextはバックグラウンドコンテキストが保存したときに変更を自動的に取得し、手動でのデータ再取得なしにUIを更新します。

永続ストアとSQLite

NSPersistentStoreCoordinatorは物理データストアを管理します。ファイルを開き、モデルに基づいてSQLiteテーブルを作成し、スキーマ変更時にマイグレーションを実行します。NSSQLiteStoreTypeでNSPersistentStoreDescriptionを初期化すると、Core Dataは.xcdatamodeldモデルに一致するスキーマのSQLiteファイルを作成します。

Core DataはSELECT/INSERT/UPDATEによる標準SQLクエリを使用しません。代わりに、モデルとNSFetchRequestを介して行われるクエリに基づいて内部SQLコマンドを生成します。開発者は起動引数-com.apple.CoreData.SQLDebug 1を使用してSQLロギングを有効にし、クエリパフォーマンスをデバッグできます。

Core Dataのマイグレーション

軽量マイグレーションは、新しい属性の追加、optional/requiredフラグの変更、renamingIDによる名前変更時にSQLiteスキーマを自動的に更新するプロセスです。エンティティのマージや分割などの根本的なスキーマ変更には重量マイグレーションが必要で、カスタムNSMigrationManagerを介して実行されます。

swift
let description = NSPersistentStoreDescription()
description.url = FileManager.default
    .urls(for: .documentDirectory, in: .userDomainMask)
    .first?
    .appendingPathComponent("Model.sqlite")
description.setOption(true as NSNumber,
    forKey: NSMigratePersistentStoresAutomaticallyOption)
description.setOption(true as NSNumber,
    forKey: NSInferMappingModelAutomaticallyOption)

let container = NSPersistentContainer(name: "AppModel")
container.persistentStoreDescriptions = [description]
container.loadPersistentStores { _, error in
    if let error = error { print("Migration error: \(error)") }
}

NSMigratePersistentStoresAutomaticallyOptionとNSInferMappingModelAutomaticallyOptionによる自動マイグレーションの設定により、Core Dataはモデルの新しいバージョンで属性やエンティティが追加されたときに、SQLiteファイルを独立して更新できます。マイグレーションが不可能な場合、ストアコーディネーターは理由の説明とともにエラーをスローします。開発者はNSMigrationManagerを介してカスタムマイグレーションを実装する必要があります。

Core Dataの実践:コードと例

NSFetchRequestはCore Dataからオブジェクトを取得するための主要なツールです。リクエストにはエンティティ名、述語(フィルター)、並べ替え記述子、制限、オフセットが含まれます。結果はNSManagedObjectまたは型付けされたサブクラスの配列として返されます。NSPredicateはAND、OR、IN、LIKE、サブクエリを使用した複雑な条件をサポートします。

NSBatchDeleteRequestは、各オブジェクトをメモリにロードせずに一括削除する効率的な方法です。リクエストはSQLiteレベルで実行され、管理対象オブジェクトコンテキストをバイパスし、完了後にのみコンテキストを更新します。更新(NSBatchUpdateRequest)と挿入(NSBatchInsertRequest)にも同様のバッチリクエストがあります。

CRUD操作の例

CRUD(作成、読み取り、更新、削除)はCore Dataではコンテキストメソッド(insert、fetch、save、delete)を介して実行されます。すべての変更はcontext.save()が呼び出されるまで一時的です。このメソッドは変更を永続SQLiteストアに保存します。保存エラー時、コンテキストは再試行のために変更された状態のままになります。

swift
let context = container.viewContext

// 作成
let user = User(context: context)
user.id = 42
user.name = "Alice"

// 読み取り
let request = User.fetchRequest()
request.predicate = NSPredicate(format: "name CONTAINS %@", "Ali")
request.sortDescriptors = [NSSortDescriptor(key: "name", ascending: true)]
let results = try context.fetch(request)

// 更新
results.first?.name = "Alice Updated"

// 削除
if let first = results.first { context.delete(first) }

// 保存
try context.save()

コンテキストの保存(context.save())は重要な操作です。saveが呼び出されない場合、すべての変更はメモリ内にのみ残ります。コンテキストはhasChanges状態を追跡し、保存前に確認できます。バックグラウンド操作には、独自の保存を持つnewBackgroundContextを使用し、UIには、タイマーまたはアプリがバックグラウンドに入ったときの自動保存付きviewContextを使用します。

Core Dataのベストプラクティス

最初のプラクティス — NSPersistentCloudKitContainerを使用してiCloud経由でユーザーデバイス間のデータを同期します。クラウド同期は、永続ストアの説明にCloudKitオプションを追加することで有効になります。Core Dataは自動的に同期の競合を管理し、他のデバイスからの変更をマージします。

2番目のプラクティス — 大きなテーブルで述語なしのfetchRequestを避けてください。無条件のフェッチはすべてのエンティティオブジェクトをメモリにロードし、高いRAM消費とUIの遅延を引き起こします。常に述語と制限を使用してください。ページネーションには、NSFetchRequestでfetchLimitとfetchOffsetを使用します。

3番目のプラクティス — マルチスレッドアクセスでの競合を解決するためにmergePolicyを構成します。NSMergeByPropertyObjectTrumpMergePolicyは最後に保存されたコンテキストから競合するプロパティを更新します。NSRollbackMergePolicyは競合時に現在のコンテキストの変更を破棄します。ポリシーの選択はアプリケーションのビジネスロジックに依存します。

4番目のプラクティス — テーブルとコレクションの統合にはNSFetchedResultsControllerを使用します。これは自動的にNSManagedObjectContextDidSave通知を購読し、必要なオブジェクトのみをロードし(フォールティング)、UITableViewアニメーションのための適切なインデックスパスとともに挿入、削除、移動をデリゲートに通知します。

パフォーマンス:プリフェッチングとフォールティング

フォールティングはCore Dataの遅延ロードメカニズムです。フェッチリクエストによって返された管理対象オブジェクトはフォールト状態にあります。その属性は完全にはロードされておらず、識別子のみです。完全なロード(フォールト発火)は任意の属性への最初のアクセス時に発生します。リレーションシッププリフェッチング(setRelationshipKeyPathsForPrefetching)は関連オブジェクトを事前にロードし、N+1クエリを回避します。

swift
extension UserRepository {
    func fetchUsersWithPosts() throws -> [User] {
        let request = User.fetchRequest()
        request.predicate = NSPredicate(format: "isActive == YES")
        request.relationshipKeyPathsForPrefetching = ["posts"]
        request.returnsObjectsAsFaults = false
        request.fetchBatchSize = 20

        let context = container.viewContext
        return try context.fetch(request)
    }
}

fetchBatchSize = 20は、Core Dataにテーブル全体を一度にロードせずに20オブジェクトのバッチでデータをロード(画面表示用)させます。returnsObjectsAsFaults = falseフラグはすべてのユーザー属性が即座にロードされることを保証し、直接表示に役立ちます。“posts”リレーションシップのプリフェッチングは、投稿にアクセスする際にユーザーごとに個別のクエリを回避します。

よくある質問

Core Dataはデータベースですか?

いいえ、Core Dataはオブジェクトグラフ管理フレームワークです。オブジェクトの操作、変更の追跡、永続化のためのAPIを提供します。Core Dataの内部のデータベース(デフォルトではSQLite)をフレームワーク自体と混同しないでください。Core DataはORMであり、DBMSではありません。

Core DataをSQLiteなしで使用できますか?

はい、Core DataはSQLite、Binary、In-Memoryの3つのストアタイプをサポートしています。ストアタイプはNSPersistentStoreDescriptionを介して設定します。In-Memoryストアはデータをディスクに永続化せず、ユニットテストに適しています。Binaryストアはコンパクトなオブジェクトセット用のレガシー形式です。

Core Dataを新しいモデルバージョンに移行するには?

軽量マイグレーションの場合は、NSMigratePersistentStoresAutomaticallyOptionとNSInferMappingModelAutomaticallyOptionを有効にします。複雑な変更の場合は、Xcodeを介してMapping Model(.xcmappingmodel)を作成します。CloudKitストア(NSPersistentCloudKitContainer)はiCloudサーバーとスキーマを同期する際に自動的にマイグレーションをサポートします。

Core DataとSwiftDataの違いは?

SwiftDataは、Swift MacrosとSwift Concurrencyを使用してCore Data上に構築された新しいAppleフレームワーク(iOS 17+)です。SwiftDataの構文はよりシンプルです。エンティティは@Modelマクロで記述され、コンテキストは@Environment(\.modelContext)で記述されます。内部では、SwiftDataは同じCore DataスタックとSQLiteを使用しています。

遅いCore Dataクエリをデバッグするには?

起動引数-com.apple.CoreData.SQLDebug 1を有効にします。Core DataはすべてのSQLクエリとその実行時間をXcodeコンソールに出力します。プロファイリングには、Core Dataテンプレートを使用したInstrumentsを使用します。これにより、フォールトリクエストの数、オブジェクトのロード時間、コンテキストの保存時間が表示されます。

まとめ

  • Core DataはiOSおよびmacOS向けのオブジェクトグラフ管理および永続化フレームワークで、デフォルトストアとしてSQLiteを使用します。
  • Core Dataスタックには、統合設定のためのNSManagedObjectModel、NSPersistentStoreCoordinator、NSManagedObjectContext、NSPersistentContainerが含まれます。
  • NSManagedObjectContextは変更追跡、元に戻しサポート、バックグラウンドコンテキストからの自動マージを備えたワークスペースです。
  • NSFetchRequestとNSPredicateおよびリレーションシッププリフェッチングが主要なフェッチツールであり、バッチサイズとフォールティングによって最適化されます。
  • 軽量マイグレーションは、モデルの新しいバージョンで属性やエンティティが追加されたときにSQLiteスキーマを自動的に更新します。
  • NSPersistentCloudKitContainerは、自動競合解決を備えたユーザーデバイス間のiCloud同期を追加します。
  • 推奨事項 — 階層的なオブジェクトモデルを持つiOSアプリケーションにはCore Dataを使用してください。単純なローカルストレージにはGRDBまたはSwiftDataを検討してください。

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください