[SwiftUI][CoreData] SwiftUI と MVVM で始める CoreData 入門 (その1:テンプレートコードの修正)

     
⌛️ 2 min.
SwiftUI と CoreData を組み合わせたアプリの作り方を説明します。

環境&対象

以下の環境で動作確認を行なっています。

  • macOS Catalina 10.15.7
  • Xcode 12.2
  • iOS 14.2

Xcode12.2 で、CoreData を選択したときに生成されるコードに一部不具合があるので、修正しつつ、説明していきます。

どんなアプリを作るか

いわゆる TODO アプリを作ってみます。

全体の方針としては、以下です。

  • TDD で開発していく
  • MVVM に沿う形にする

 

段階を追って、以下のような機能を作っていきます。

  • TODO 項目を、作成・削除・修正 できるようにする(基本機能)
  • TODO に機能追加(例えばアラームの追加?)
  • iCloud 経由での同期

プロジェクト作成

以下の設定で作成します。

  • Multiplatform プロジェクト  iOS プロジェクト
  • プロジェクト名:MyTODO, ☑️ Use CoreData, ☑️ Include Tests
  • 保存フォルダ、”Create Git repository on my Mac” 設定 は、お好みで
Project設定 Page1
Project設定 Page1
Project設定 Page2
Project設定 Page2
注意

Multiplatform プロジェクトで作成すると、UnitTest を行う時に問題が発生してしまいますので、iOS プロジェクトで作成する必要があります。

作成されたプロジェクト

作成されたプロジェクトに含まれる swift ファイルは、5つあります。

  • アプリケーション本体向けファイル
    MyTODOApp.swift
    App に準拠した struct を定義しています。
    ContentView.swift
    App が表示するビューを定義しています
    Persistence.swift
    CoreData 関連のコードがまとめられています
  • テスト向けファイル
    MyTODOTests.swift
    UnitTest テストコード
    MyTODOUITests.swift
    UI UnitTest テストコード

最初に、Xcode が生成したコードに含まれている問題を修正します。

CoreData 向けプロジェクトで生成されたコードが含む問題

問題の症状

起動しても何も表示されず、新しい要素を追加したり編集したりするための UI も表示されません。

ContentView に着目して、body の部分を抜粋すると以下のような内容になっています。

ContentView.body


    var body: some View {
        List {
            ForEach(items) { item in
                Text("Item at \(item.timestamp!, formatter: itemFormatter)")
            }
            .onDelete(perform: deleteItems)
        }
        .toolbar {
            #if os(iOS)
            EditButton()
            #endif

            Button(action: addItem) {
                Label("Add Item", systemImage: "plus")
            }
        }
    }

パッと見では EditButton と + のボタンが表示されるような雰囲気ですが、以下のようなスクリーンが現れます。

生成されたコードをそのままビルドして実行した結果
生成されたコードをそのままビルドして実行した結果

何も表示されません。

問題点

以下が問題の原因です。

  • NavigationView に wrap されていないので、ツールバー相当がそもそも画面上に存在しない
    ➡️ ドキュメントに明確に書かれていませんが、現時点で iOS では、NavigationView に含まれるビューにしないとツールバー 上のアイテムは表示されません。
  • .toolbar で複数の View を指定しているが、ViewBuilder ではないので、1つしか表示されない
    ➡️ そもそも表示されないのですが、表示されたとしても、期待する表示になりません。
  • ToolbarItem を使って表示位置を制御するのが、新しい作法なのに、使っていない
    ➡️ 理想的には、Context を指定して、OS が表示位置を決める方が良いと思われます。iOS のみをターゲットにするのであれば、場所指定でもありです。

問題を修正

以下のように、修正しました。

修正後


    var body: some View {
        // (1)
        NavigationView {
            List {
                ForEach(items) { item in
                    Text("Item at \(item.timestamp!, formatter: itemFormatter)")
                }
                .onDelete(perform: deleteItems)
            }
            .toolbar {
                // (2)
                #if os(iOS)
                ToolbarItem(placement: .navigationBarLeading) {
                    EditButton()
                }
                #endif

                // (3)
                ToolbarItem(placement: .navigationBarTrailing) {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        }
    }
コード解説
  1. .toolbar modifier を使用して配置したいので、NavigationView で wrap しました
  2. ToolbarItem を使用して、EditButton を NavigationBar の左側に表示するようにしました
  3. ToolbarItem を使用して、追加ボタン(+ボタン) を NavigationBar の右側に表示するようにしました

こうすることで、起動後のスクリーンが以下のようになります。

起動直後のスクリーン(修正後)
起動直後のスクリーン(修正後)

+ ボタンを押すと要素を追加することができるようになっています。

これで、当初のサンプルプロジェクトを操作して試すことができるようになりました。

次回は、TODO アプリにするために、最初から定義されている Item という CoreData 要素を変更していきます

まとめ:Xcode12.2 で CoreData プロジェクトを作ると最初に一手間必要

Xcode12.2 で CoreData プロジェクトを作ると最初に一手間必要
  • ツールバー が期待通りに表示されないので、修正が必要

説明は以上です。
不明な点やおかしな点ありましたら、こちらまで。

CoreData おすすめ本

CoreData の本は、多く出ているわけではないのですが、以下の本が おすすめです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です