忙しい人のための5分でSwiftDataの雰囲気をキャッチアップするメモ

# 本記事について

本記事では、SwiftDataをざっくりキャッチアップしたメモです。
SwiftDataは、CoreDataのようにデータを永続化するフレームワークです。

今回はなんとなくSwiftDataの雰囲気を掴めることをゴールとします。

新規でプロジェクトと作るとSwiftDataの実装がすでに組み込まれています。
デフォルトで用意されている実装を使って解説します。


# 環境

- Xcode: 15.1
- iOS: 17.2
- MacBool Air M2 / Sonoma 14.2.1

# 事前準備

下記3点を行います。

- Xcodeで新規プロジェクトを作る。
- 新規プロジェクト設定画面でStorageをSwiftDataに設定する。
- OSの条件分岐は説明しないので削除する。

# 解説

## モデルの設定

アプリのエントリポイントです。
データベース操作を行うための環境の準備を行います。

```SampleSwiftDataApp.swift
@main
struct SampleSwiftDataApp: App {
    var sharedModelContainer: ModelContainer = {
        let schema = Schema([
            Item.self,
        ])
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)

        do {
            return try ModelContainer(for: schema, configurations: [modelConfiguration])
        } catch {
            fatalError("Could not create ModelContainer: \(error)")
        }
    }()

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(sharedModelContainer)
    }
}

```

### スキーマを定義


```swift
let schema = Schema([
            Item.self,
        ])
```

https://developer.apple.com/documentation/swiftdata/schema

### 定義したスキーマを使ってモデルの設定

```swift
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
```

https://developer.apple.com/documentation/swiftdata/modelconfiguration

### ModelContainerの構築

```swift
ModelContainer(for: schema, configurations: [modelConfiguration])
```

最後にModelContainerを返します。
ModelContainerによって、データの操作を行います。

https://developer.apple.com/documentation/swiftdata/modelcontainer


## モデル定義

```Item.swift
@Model
final class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}
```

### `@Model`マクロ

- `@Model`マクロでItem型のモデルクラスを定義します。
- Itemインスタンスを保存できます。

https://developer.apple.com/documentation/swiftdata/model()

## View側

次にView側の説明です。

```ContentView.swift
import SwiftUI
import SwiftData

struct ContentView: View {
    // 解説
    @Environment(\.modelContext) private var modelContext
    // 解説
    @Query private var items: [Item]

    var body: some View {
        NavigationSplitView {
            List {
                ForEach(items) { item in
                    NavigationLink {
                        Text("Item at \(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))")
                    } label: {
                        Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
                    }
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            Text("Select an item")
        }
    }

    private func addItem() {
        withAnimation {
            let newItem = Item(timestamp: Date())
            // 解説
            modelContext.insert(newItem)
        }
    }

    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                // 解説
                modelContext.delete(items[index])
            }
        }
    }
}

// 解説
#Preview {
    ContentView()
        .modelContainer(for: Item.self, inMemory: true)
}

```

### モデルのフェッチ、挿入、削除、および変更への保存可能なオブジェクト

```swift
@Environment(\.modelContext) private var modelContext
```

https://developer.apple.com/documentation/SwiftUI/EnvironmentValues/modelContext

### 指定したモデルをfetchし、データ管理を行う

```swift
@Query private var items: [Item]
```

https://developer.apple.com/documentation/swiftdata/query

サンプルだと、配列化するだけですが、
公式だと下記のようにソートなども可能です。

```swift
@Query(sort: \.startDate, order: .reverse)
```

### データの追加・削除

```swift
modelContext.insert(newItem)

modelContext.delete(items[index])
```

### View内でデータ操作を行うためのモディファイア

Xcode Preview内でデータ操作を行うことができます。ただし、データ保存までは行いません。

```swift
ContentView()
    .modelContainer(for: Item.self, inMemory: true)
```



# 最後に

雰囲気を掴んでいただけたら嬉しいです。

# 参考文献

- https://developer.apple.com/xcode/swiftdata/
- https://developer.apple.com/documentation/swiftdata
- [Preserving your app’s model data across launches
](https://developer.apple.com/documentation/swiftdata/preserving-your-apps-model-data-across-launches)
- https://ramble.impl.co.jp/6959/#toc1