💾

【WWDC23】SwiftDataを用いたApp作成

2024/06/24に公開

SwiftUIとSwiftDataを用いたフラッシュカードアプリの作成

公式のサンプルを参考に記事を記載します。

モデルの定義

モデルクラスをSwiftDataに対応させます。以下のようにCardクラスを定義し、@Modelマクロを追加します。@Modelマクロを使用することによって、Observableプロトコルに一致するようになり、ObservableObjectの代わりに使えます。

import SwiftData

@Model
final class Card {
    var front: String
    var back: String
    var creationDate: Date

    init(front: String, back: String, creationDate: Date = .now) {
        self.front = front
        self.back = back
        self.creationDate = creationDate
    }
}

この@Modelマクロにより、Cardクラスは自動的に永続化が可能になります。

データのバインディング

@Bindableプロパティラッパーを使用して、データモデルをViewにバインドします。

@Bindable var card: Card

これにより、テキストフィールドなどのUI要素が直接モデルにバインドされ、モデルの変更が自動的にUIに反映されます。

データのクエリ

SwiftDataからデータをクエリして表示するには、@Queryを使用します。

@Query private var cards: [Card]

@QueryはSwiftDataからモデルをクエリし、モデルの変更がViewに反映されるようにします。

モデルコンテナの設定

モデルコンテナの設定方法に関してです。

WindowGroupでモデルコンテナを設定することによって、WindowGroup全体でモデルを使用できます。

Windowごとに複数のモデルコンテナを設定できます。

下位の階層内において、別でモデルコンテナを設定できます。

WindowGroupシーンのモデルコンテナを設定します。これにより、ViewがSwiftDataにアクセスできます。

WindowGroup {
    ContentView()
}
.modelContainer(for: Card.self)

Previewの表示

サンプルデータを用意します。

struct SampleDeck {
    static var contents: [Card] = [
        Card(front: "Open Settings in a single click", back: "SettingsLink"),
        Card(front: "Configure the toolbar title display size", back: "toolbarTitleDisplayMode(_:)"),
        //省略
    ]
}

Previewコンテナを作成します。

@MainActor
let previewContainer: ModelContainer = {
    do {
        // ModelContainerを作成し、データをメモリ内にのみ保存し、永続化ストレージを使用せずに使用する設定を追加
        let container = try ModelContainer(
            for: Card.self,
            configurations: ModelConfiguration(isStoredInMemoryOnly: true)
        )
        let modelContext = container.mainContext

        // モデルコンテキストに既存のデータがない場合、サンプルデータを挿入
        if try modelContext.fetch(FetchDescriptor<Card>()).isEmpty {
            SampleDeck.contents.forEach { container.mainContext.insert($0) }
        }
        return container
    } catch {
        // コンテナの作成に失敗した場合、エラーメッセージを出力しアプリケーションを終了
        fatalError("Failed to create container")
    }
}()

PreviewpreviewContainerを設定する。

#Preview {
    ContentView()
        .frame(minWidth: 500, minHeight: 500)
        .modelContainer(previewContainer)
}

モデルコンテキストへのアクセス

モデルコンテキストにアクセスして新しいデータを保存します。SwiftUIでは、Environmentを使用してモデルコンテキストにアクセスします。

@Environment(\.modelContext) private var modelContext

新しいデータを作成し、モデルコンテキストに挿入します。

let newCard = Card(front: "Sample Front", back: "Sample Back")
modelContext.insert(object: newCard)

ドキュメントベースのアプリケーション設定

ドキュメントベースのアプリケーションを設定します。これにより、ドキュメントデータを作成、保存、共有が可能となります。まず、info.plistでドキュメントデータのタイトル・拡張子・identifier(コード内と同一)・ConformsToを設定します。

info.plistで設定したデータ・ファイル形式を使用するために宣言します。

import UniformTypeIdentifiers

extension UTType {
    static var flashCards = UTType(exportedAs: "com.example.flashCards")
}

DocumentGroupcontentTypeを指定して完了です。

@main
struct SwiftDataFlashCardSample: App {
    var body: some Scene {
        #if os(iOS) || os(macOS)
        DocumentGroup(editing: Card.self, contentType: .flashCards) {
            ContentView()
        }
        #else
        WindowGroup {
            ContentView()
                .modelContainer(for: Card.self)
        }
        #endif
    }
}

上記の設定・実装を行うことにより、オリジナルのドキュメントデータを作成し、管理することが可能です。

最後に

間違い・気になる部分がありましたら、コメントいただけると大変うれしいです。
良かったと思ったら記事へのいいねXのフォローをよろしくお願いいたします。

https://sites.google.com/view/muranakar

個人でアプリを作成しています。良かったら覗いてみてください。

参考資料

https://developer.apple.com/videos/play/wwdc2023/10154/

Discussion