Swift UI CoreDataのサンプルプロジェクトを解説

表題の通りダルいが解説

ContentsView構造体定義からbody変数

画像1

@Environment(\.managedObjectContext) private var viewContext

ローカル変数viewContextの定義だと思う@Environment(\.managedObjectContext)というのは「マネージドオブジェクト」というやつらしい。

@FetchRequest(
       sortDescriptors: [NSSortDescriptor(keyPath: \Item.timestamp, ascending: true)],
       animation: .default)
   private var items: FetchedResults<Item>

同様な読み方をすると次はこのローカル変数itemsの定義。@FetchRequestという接頭辞にsortDescriptorsとanimationオプションが付いてるんだろう

var body: some View {

次。

(Root)
∟ ContentsView
|    ∟ body
|    ∟ addItem
|    ∟ deleteItems
∟ itemFormatter
∟ ContentsView_Preview

someというのは「何か」らしい。Viewみたいなもののサブクラス。。じゃなくて構造体

NavigationView {
           List {
               ForEach(items) { item in
                   NavigationLink {
                       Text("Item at \(item.timestamp!, formatter: itemFormatter)")
                   } label: {
                       Text(item.timestamp!, formatter: itemFormatter)
                   }
               }
               .onDelete(perform: deleteItems)
           }

次。この辺までitemsをforeachしてる要素は全部NavigationLinkで作るようだ(NavigationLinkは画面遷移する時に使うやつ)

 ​.toolbar {
               ToolbarItem(placement: .navigationBarTrailing) {
                   EditButton()
               }
               ToolbarItem {
                   Button(action: addItem) {
                       Label("Add Item", systemImage: "plus")
                   }
               }
           }
           Text("Select an item")

次。メソッドチェーンでtoolbarをつなげている。
この中にToolbarItemが2固定義されておりこれが画面右上のボタン2つ(+,Edit)

  Text("Select an item")

これはどこにあるかわからん

addItemとdeleteItemsメソッド

画像2

次。

(Root)
∟ ContentsView
|    ∟ body
|    ∟ addItem
|    ∟ deleteItems
∟ itemFormatter
∟ ContentsView_Preview

body変数は上記でおしまいです。body変数と同じレベルにある表題2つのメソッドについてです。まずaddItem

let newItem = Item(context: viewContext)
           newItem.timestamp = Date()
do {
try viewContext.save()
           } catch {
               // Replace this implementation with code to handle the error appropriately.
               // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
               let nsError = error as NSError
               fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
           }

1行目でItemオブジェクト作成。
▼Itemオブジェクトの元になってる定義

画像3

Itemオブジェクトってのはあらかじめ勝手に作成しといてくれていたCoreDataのオブジェクト。

newItem.timestamp = Date()

次。作ったオブジェクトに値設定

 ​try viewContext.save()

次。セーブ。
次delete

offsets.map { items[$0] }.forEach(viewContext.delete)
do {
try viewContext.save()
           } catch {
               // Replace this implementation with code to handle the error appropriately.
               // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
               let nsError = error as NSError
               fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
           }

これはメソッドの説明をしたい
▼onDeleteメソッド

画像4

@inlinable public func onDelete(perform action: ((IndexSet) -> Void)?) -> some DynamicViewContent

▼deleteItems

private func deleteItems(offsets: IndexSet) {

▼deleteItemsの呼び出し元

ForEach(items) { 
略
               }
               .onDelete(perform: deleteItems)

deleteItemsメソッドをonDeleteに渡している。onDeleteの引数の定義は以下である。

action: ((IndexSet) -> Void)?

まず?なので指定しなくても良さそう。
指定するならIndexSet型の変数を受け取るメソッドを定義できるらしい。
そしてこの変数は選択された行を受け取るらしい。

offsets.map { items[$0] }.forEach(viewContext.delete)

では、中の処理だが、これ。
$0にoffsets:IndexSetのそれぞれが入ってくる

▼参考:https://developer.apple.com/documentation/foundation/indexset

画像8


そしてitemsはローカル変数であるitemsの選んだ(引数として渡された)要素のそれぞれに対し(forEach)
viewContext.delete
するらしい。

itemFormatter変数とContentView_Previews構造体

画像6


(Root)
∟ ContentsView
|    ∟ body
|    ∟ addItem
|    ∟ deleteItems
itemFormatter
ContentsView_Preview

最後だがまず最後のContentView_Previews構造体に関しては最初に作られるやつだからよくわからんけどおけ

itemFormatter: DateFormatter
まずスコープがContentView構造体と同じレベル。
ContentView内で画面表示用に使う日付見た目整形用構造体。以上。

所感

なぜSwiftUIを調べているかだが、storyboardでiOSプロジェクトを複数人で作ると(バージョン管理しながら)storyboardの変更履歴がカオスなことになるらしい。
そして世の中にはそれが理由のためかstoryboardを使わずにコードビハインドのViewControllerに全部書く人がいたりそういうプロジェクトを見たことがある。これはそれを考慮したためかもしれない。
個人的にはビューとコードビハインドという作りが好きであるが(UIはIQ1でGUIで組み立てられるし)そういう問題があるならそちらに対応した方が良いのかもしれないという思いもあることが動機である。
あとコード量もすごい減るらしいし。
時代に対応していくのはダルいが、いざ会社でiOSアプリ作ってと言われて工数だけ渡されたら技術選定として上記storyboardがカオスになることを鑑みるとこのようなコードでUIを組み立てられる技術を選ぶかもしれなくそうなった時にやはり知っていないと詰むし何より楽するために仕方なく調べているわけである。
なお他にマルチプラットフォームで HTML/CSSでUIを組めるのもSwiftUIの代わりに良いかもしれないがあれはあれでビルドにバカ時間かかるしホットデプロイみたいな感じでサクサクできる面もあるが結局テストで実機用にビルドしなければいけないあたりなかなかキツイなぁとも思う。

今出してるアプリをSwiftUIで置き換えるというのが王道か。




この記事が気に入ったらサポートをしてみませんか?