SwiftUIで行こう! Core Dataでリスト。
SwiftUIでCoreDataを使ってみましょう!
参考サイトを見るとなんとなく簡単にできる感じなの自分でもやってみます。
CoreDataってなんだかとっつきにくい印象なのでこの機会に少しでも理解したいです。
まずiOSの新規プロジェクトを作って、CoreData のEntitiesを作っていきます。
左から、ファイルを選んでいきます。ファイル名は
自分のプロジェクト名.xcdatamodeld (今回だと"coredata.xcdatamodeld")
です。
ENTITIESの名前をつけます。ダブルクリックで入力できます。そしてAttributeを作っていきます。"+"を押して必要なものを作ります。Typeはその部分をクリックして選択できます。
これでデータベースでいうフィールド定義、必要なデータ、そしてその種類の定義が終わりました。
続いて新しいファイルを作ります。これで今作ったENTITIESを呼び出すことができるようになります。(Task+Extensionsと名前をつけています)
そしてメインのファイル、ContentView.swiftを編集していきます。
参考サイトのようにコードを追加していきます。
要点としては、 まず、全体をコントロールすることになる変数です。
@Environment
@State
@FetchRequest
@Environment(\.managedObjectContext) var context
については
SceneDelegate.swiftの中で 23 〜27 行目に context として宣言してあります。
そして、実際に表示するところをコードする
var body: some View{}
を作ります。まず変数を@Stateで宣言。
@State private var taskName: String = ""
入力部位を作ります。ここで入力したデータを"taskName"にデータを入れます。ここで気をつけるのが$をつけることです。
TextField("Task Name", text: $taskName)
次にこの入力したデータを記録していくコードを書いていきます。
Button(action: {
self.addTask()
}){
Text("Add Task")
}
"Add Task"ボタンを押したタイミングで関数”addTask()”を実行します。
そのaddTaskですが、ContentView: Viewの中でvar body: some Viewの直下にコードを配置します。
func addTask() {
let newTask = Task(context: context)
newTask.id = UUID()
newTask.isComplete = false
newTask.name = taskName
newTask.dateAdded = Date()
do {
try context.save()
} catch {
print(error)
}
}
データの記録はこれでできるようになりました。あとほリスト表示をしたいのでそのためのコードを書いていきます。まず、変数宣言です。
@FetchRequest(
entity: Task.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Task.dateAdded, ascending: false)],
predicate: NSPredicate(format: "isComplete == %@", NSNumber(value: false))
) var notCompletedTasks: FetchedResults<Task>
そしてリストです。
List {
ForEach(notCompletedTasks){ task in
TaskRow(task: task)
}
}
これを縦に並べたいのでVStackを使って表示させます。イメージは
VStack {
HStack{
TextField()
Button()
}
List()
}
という感じになります。リストの中身ですが、
TaskRow(task: task)
としています。この中身については構造体で宣言します。
struct TaskRow: View {
var task: Task
var body: some View {
Text(task.name ?? "No name given")
}
}
ContentViewの外で宣言します。最後にリストから削除するときの命令を書いていきます。関数で
func updateTask(_ task: Task){
let isComplete = true
let taskID = task.id! as NSUUID
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Task")
fetchRequest.predicate = NSPredicate(format: "id == %@", taskID as CVarArg)
fetchRequest.fetchLimit = 1
do {
let test = try context.fetch(fetchRequest)
let taskUpdate = test[0] as! NSManagedObject
taskUpdate.setValue(isComplete, forKey: "isComplete")
} catch {
print(error)
}
}
addTask()の直下に記述します。ここでの注意点。
import CoreData
でCoreDataをインポートしないとNSFetchRequestが動かず、エラーがでます。
これで、入力を受付、データの格納、表示、そして再度押すと削除される一連の動作ができるようになります。
ポイントは
@FetchRequest(
entity: Task.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Task.dateAdded, ascending: false)],
predicate: NSPredicate(format: "isComplete == %@", NSNumber(value: false))
) var notCompletedTasks: FetchedResults<Task>
と
func updateTask(_ task: Task){
let isComplete = true
let taskID = task.id! as NSUUID
let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: "Task")
fetchRequest.predicate = NSPredicate(format: "id == %@", taskID as CVarArg)
fetchRequest.fetchLimit = 1
do {
let test = try context.fetch(fetchRequest)
let taskUpdate = test[0] as! NSManagedObject
taskUpdate.setValue(isComplete, forKey: "isComplete")
} catch {
print(error)
}
}
の部分のようなのでまた復習したいと思います。