Closed tora-muscle closed 1 year ago
▼ SwiftUI で使えるローカル DB には何がある?
Core Data
Appleが提供するオブジェクトグラフと永続性のフレームワーク。SwiftUIと相性が良く、データベース内の項目が変更されると、テーブルは自動的に更新される[1]。長所としては、高速で安全なデータアクセスやバージョン管理などの機能。短所としては、コード量が多くなりやすく、複雑なデータモデルを扱う場合は設計や管理が難しくなりがち。
Realm Database
Realm社が提供するオープンソースのモバイル向けデータベース。Macアプリでも使用可能。長所としては、パフォーマンスが良く、コーディングが楽で直感的。短所としては、SwiftUIとの連携には追加のライブラリやコードが必要。
UserDefaults
Appleが提供するキー値ペア形式のデータストレージです。SwiftUI2.0から単純なデータのファイル保存程度はできるようになっている[2]。長所としては、簡単に使えること。短所としては、大量や複雑なデータを保存することには向いていない。
▼ どの観点で絞っていく?
要素の入れ替えのしやすさ
できるだけ少ないコード量でリポジトリパターンを意識した構成を実現できる DB を採用したい
firebaseへの移行のしやすさ
二次開発で firebase に移行することを考えると、操作方法、内部構成が firebase にできる限り似たものを採用したい
▼ firebase に移行しやすいものは?
Realm Database or UserDefaults
Realm Database は Firebase Realtime Database と同じようにオブジェクト指向のデータベースであり、データ構造や操作方法が似ている[4]。UserDefaults はキー値ペア形式のデータストレージであり、Firebase Cloud Firestore と同じようにドキュメント指向のデータベースであり、データ構造や操作方法が似ている[5],[6]。が、複雑なデータを扱う本アプリには向いていないと思われる。▼ 1weekPDCA には Firebase Realtime Database と Firebase Cloud Firestore どちらが相応しい?
Firebase Cloud Firestore
▼ 結果
Realm Database
を採用📚 参考文献
@FocusState
を参照しているため、 TextField がフォーカスされているかの状態管理が適切に行われていない可能性があるfunc updateTaskTitle(taskCardId: String, with newTaskTitle: String, taskCardManager: TaskCardManager) {
// ID が一致する要素がなかった場合処理を中断する
guard let taskCardData = realm.object(ofType: TaskCardData.self, forPrimaryKey: taskCardId) else {
return
}
try! realm.write {
taskCardData.taskTitle = newTaskTitle
print("New Text = \(taskCardManager.taskCardData[0].taskTitle)")
// 状態を更新する
taskCardManager.reloadTaskCardData()
print("New Text = \(taskCardManager.taskCardData[0].taskTitle)")
}
}
2023-03-07 14:38:24.504300+0900 1weekPDCA[1023:121522] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
New Text = タスク1つ目 追加文言
New Text = タスク1つ目 # DB 状態反映後の text が更新前のものになっている
New Text = タスク1つ目 # 2回呼び出されている
New Text = タスク1つ目
[ ] TaskCardListView
からTaskCard
、TodoCard
を切り出し、それぞれの構造体につき1つの TextField 、@FocusState
を持たせることで@FocusState
の二重更新を防ぐ
[x] 状態管理の更新を「データを全消去して1から DB を読み込む」のではなく、更新された一部のデータのみ DB から ID を使って識別し、更新するようにRealmDataBaseManager
を実装し直す
@FocusState
を廃止し、TextField にonChanged
モディファイアを設定、個々に変更を検知するようにした。TextField(
"task title",
text: $taskCardManager.taskCardData[taskIndex].taskTitle,
axis: .vertical
)
.textStyle(for: .title, color: .uiColorGray)
.fixedSize(horizontal: false, vertical: true)
.onChange(
of: taskCardManager.taskCardData[taskIndex].taskTitle,
perform: { newValue in
realmDataBaseManager.updateTaskTitle(
taskCardId: taskCardManager.taskCardData[taskIndex].taskId,
with: newValue,
taskCardManager: taskCardManager
)
}
)
検証環境 : iOS 16.2.3 iPhone12Pro
View で DB 変更処理関数を直接呼び出すのではなく、TaskCardManager
を介して DB 変更処理を呼び出したい
DDDアーキテクチャを採用しているのに、プレゼンテーションとインフラが依存関係にあるから
https://github.com/k-saito-en/1weekPDCA/issues/20#issuecomment-1459092373 で、TextField の文字が1文字変更するたびに DB を全読み込みしているので、パフォーマンスが悪いから
TaskCardManager
の CRUD 関数内で DB 更新処理を呼び出し、getAllTaskCards()
を毎回呼び出さなくていいようにする
🎫 関連課題
2
✨ 実現したいこと
▼ when?
7 の前にローカル DB を実装しておきたい
▼ what?・why?
[x]
PlanDo 画面のタスクデータを保存する機能をつけたい
現時点ではタスクデータを保存する機能はなく、アプリを閉じるとデータが初期化されてしまう。最低限使えるアプリにするために、ローカルへの保存手段が欲しい。[x]
要素の並べ替え機能実装も意識したい
絶対に実装したい機能として「要素の並べ替え」がある。こちらを実現するためにも PlanDo 画面の時点で要素の並べ替え機能を実装しておきたい。🚩 やらないこと
🔀 達成条件
アプリの次回立ち上げ時にタスクデータが残っていること
タスクデータ、Todoデータの並び替えが可能であることローカル DB への保存、データの並び替えが確認できるテストコードを書き、通過すること
👀 備考