Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 60/100

core-data-patterns

macOSアプリのCore Data永続化パターンです。スタックのセットアップ、CRUD操作、リレーションシップ、マイグレーションに対応しており、データの保存と管理を効率的に実装できます。

description の原文を見る

Core Data persistence patterns for macOS apps. Stack setup, CRUD operations, relationships, migrations.

SKILL.md 本文

Core Data スキル

概要

macOS アプリケーション向けの Core Data 永続化パターン。

スタックセットアップ

actor PersistenceController {
    static let shared = PersistenceController()

    let container: NSPersistentContainer

    init(inMemory: Bool = false) {
        container = NSPersistentContainer(name: "AppModel")

        if inMemory {
            container.persistentStoreDescriptions.first?.url = URL(fileURLWithPath: "/dev/null")
        }

        container.loadPersistentStores { _, error in
            if let error {
                fatalError("Core Data failed: \(error)")
            }
        }

        container.viewContext.automaticallyMergesChangesFromParent = true
        container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    }

    var viewContext: NSManagedObjectContext {
        container.viewContext
    }

    func newBackgroundContext() -> NSManagedObjectContext {
        container.newBackgroundContext()
    }
}

エンティティパターン

@objc(Item)
public class Item: NSManagedObject {
    @NSManaged public var id: UUID
    @NSManaged public var title: String
    @NSManaged public var createdAt: Date
    @NSManaged public var updatedAt: Date
}

extension Item {
    @nonobjc public class func fetchRequest() -> NSFetchRequest<Item> {
        NSFetchRequest<Item>(entityName: "Item")
    }

    static func create(in context: NSManagedObjectContext, title: String) -> Item {
        let item = Item(context: context)
        item.id = UUID()
        item.title = title
        item.createdAt = Date()
        item.updatedAt = Date()
        return item
    }
}

フェッチリクエスト

// 基本的なフェッチ
let request = Item.fetchRequest()
request.predicate = NSPredicate(format: "title CONTAINS[cd] %@", searchText)
request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.createdAt, ascending: false)]
request.fetchLimit = 50
request.fetchBatchSize = 20

let items = try context.fetch(request)

SwiftUI 統合

struct ItemListView: View {
    @FetchRequest(
        sortDescriptors: [SortDescriptor(\.createdAt, order: .reverse)],
        animation: .default
    )
    private var items: FetchedResults<Item>

    var body: some View {
        List(items) { item in
            Text(item.title)
        }
    }
}

バックグラウンド操作

func importData(_ data: [ImportItem]) async throws {
    let context = PersistenceController.shared.newBackgroundContext()

    try await context.perform {
        for item in data {
            let entity = Item(context: context)
            entity.id = UUID()
            entity.title = item.title
        }
        try context.save()
    }
}

マイグレーション

  1. Xcode で新しいモデルバージョンを作成する
  2. 現在のバージョンとして設定する
  3. 自動マイグレーションを有効にする:
description.shouldMigrateStoreAutomatically = true
description.shouldInferMappingModelAutomatically = true

テスト

final class CoreDataTests: XCTestCase {
    var controller: PersistenceController!

    override func setUp() {
        controller = PersistenceController(inMemory: true)
    }
}

CloudKit コンテナ (DA-4)

iCloud 同期の場合、NSPersistentContainer の代わりに NSPersistentCloudKitContainer を使用してください:

let container = NSPersistentCloudKitContainer(name: "AppModel")
// セットアップ後、CloudKit 同期は自動的に実行されます
// 競合解決は NSMergeByPropertyObjectTrumpMergePolicy を使用します(ローカルが優先)

CloudKit スキーママイグレーション: CloudKit スキーマは加算専用です。フィールドやエンティティを追加することはできますが、削除や名前変更はできません。スキーマは慎重に計画してください。

導出属性 (DA-5)

導出属性を使用して、正規化されていない数値や集計を表現し、負荷の高いフェッチリクエストを回避します:

Xcode モデルエディタで:属性を選択 > Data Model Inspector > Derived > 導出式を設定します。

// 子要素の数:「children.@count」
// 最新日付:「children.@max.createdAt」

導出属性は、保存時に Core Data によって自動的に計算されます。これにより N+1 クエリの問題を回避できます。

抽象エンティティパターン (DA-6)

複数のエンティティ型で共有する属性に抽象エンティティを使用します:

AbstractBaseEntity (抽象)
  ├── id: UUID
  ├── createdAt: Date
  ├── updatedAt: Date
  │
  ├── TaskEntity (具体)
  │   └── title: String
  │
  └── NoteEntity (具体)
      └── body: String

使用する場合: 複数のエンティティが 3 個以上の同一属性を共有している。避けるべき場合: idcreatedAtupdatedAt のみが共有されている場合(各エンティティに直接追加してください。3 つのフィールドのみのために継承の複雑性は価値がありません)。

Core Data デバッグ (DA-7)

診断用の起動引数:

引数表示内容
-com.apple.CoreData.SQLDebug 1実行される SQL クエリ
-com.apple.CoreData.SQLDebug 3SQL とバインド変数
-com.apple.CoreData.MigrationDebug 1マイグレーションステップ
-com.apple.CoreData.ConcurrencyDebug 1スレッド違反
-com.apple.CoreData.CloudKitDebug 1CloudKit 同期アクティビティ

Xcode で設定:Edit Scheme > Run > Arguments > Arguments Passed On Launch。

Instruments Core Data テンプレート: フェッチ数、フォルト数、保存期間を表示します。パフォーマンスをデバッグする際に使用します。フォルト数が多い = プリフェッチされなかったオブジェクトがアクセスされている。

データ整合性制約 (DA-8)

ユニーク制約

Xcode モデルエディタで設定:エンティティを選択 > Data Model Inspector > Constraints。制約されたフィールドに重複したエントリを防ぎます。

// エンティティ:Tag
// ユニーク制約:name
// → 同じ名前の 2 つのタグは、重複を作成する代わりにマージされます

検証ルール

モデルエディタで属性ごとに追加:最小値、最大値、文字列の正規表現。

// プログラムの検証(複雑なルール用)
override func validateForInsert() throws {
    try super.validateForInsert()
    guard title.count >= 1 else {
        throw ValidationError.titleRequired
    }
}

フェッチリクエスト検証

常に開発時にモデルに対してプレディケートを検証します:

// 文字列ベースのプレディケートの代わりに、型付きキーパスを使用してください
request.predicate = NSPredicate(format: "%K == %@", #keyPath(Item.status), "active")

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
productengineered
リポジトリ
productengineered/parsely
ライセンス
MIT
最終更新
2026/4/20

Source: https://github.com/productengineered/parsely / ライセンス: MIT

本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: productengineered · productengineered/parsely · ライセンス: MIT