先日の記事で紹介したとおり、CoreDataを使った簡単なTodoアプリを作ってみた。

SwiftUIとCoreDataで一画面のTodoアプリを作ってみた

今回はこのアプリに、追加したタスクを削除してデータベースに保存する機能を実装する方法を紹介する。

コード全文

まずはコード全文を見てもらおう。

import SwiftUI
import CoreData

struct ContentView: View {
  @FetchRequest(
    sortDescriptors: [NSSortDescriptor(keyPath: \Task.name, ascending: false)],
    animation: .default
  )
  var tasks: FetchedResults<Task>
  
  @Environment(\.managedObjectContext) var viewContext
  @State var new = ""
  
  var body: some View {
    VStack {
      HStack {
        TextField("Input here", text: $new)
          .textFieldStyle(RoundedBorderTextFieldStyle())
        Button(action: {
          let newTask = Task(context: self.viewContext)
          newTask.name = self.new
          do {
            try self.viewContext.save()
          } catch {
            let nsError = error as NSError
            fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
          }
          
          self.new = ""
        }) {
          Text("追加")
        }
      }
      
      List {
        ForEach(tasks, id: \.self) { task in
          Text("\(task.name!)")
        }.onDelete(perform: removeTask)
      }
    }.padding()
  }
  
  private func removeTask(at offsets: IndexSet) {
    for index in offsets {
      let putTask = tasks[index]
      viewContext.delete(putTask)
    }
    do {
      try self.viewContext.save()
    } catch {
      let nsError = error as NSError
      fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
    }
  }
}

アプリを起動し、あらかじめいくつかのタスクを登録しておく。

CoreDataからデータを削除するメソッドを用意

今回は、データを削除するメソッドを新たに用意する。

private func removeTask(at offsets: IndexSet) {
  for index in offsets {
    let putTask = tasks[index]
    viewContext.delete(putTask)
  }
  do {
    try self.viewContext.save()
  } catch {
    let nsError = error as NSError
    fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
  }
}

主な処理は2〜5行目。

offsetsには削除対象の要素番号が入るので、これを使って要素番号に対応するエンティティを削除する。

do〜以降はデータベースへの保存処理。

ListビューのonDeleteメソッドを定義する

あとはListビューのonDeleteメソッドに、用意したremoveTaskを渡せば良い。

List {
  ForEach(tasks, id: \.self) { task in
    Text("\(task.name!)")
  }.onDelete(perform: removeTask)
}

アプリを実行し確認してみよう。

タスクを左へスワイプすると、Deleteボタンが表れる。

Deleteボタンをタップするとリストから削除され、またアプリを再起動しても変更内容が保存されていることが分かる。