I have made a very simple app in SwiftUI. ToDo List using Core Data. I can add to do items and store them with Core Data. Items are presented on a list in ContentView. Tapping each item brings us to EditItemView. I have managed to show correct data for each entry. From this view I would like to delete this particular entry I see in EditItemView. It should work similar to deleting lists in Reminders app on iOS. Delete button should delete this particular entry and take us back to ContentView. But... nothing happens. I am not getting any errors, but nothing is deleted as well.
Core Data In Core Data I have 1 entity: ToDoItem (Module: Current Product Module, Codegen: Class Definition) Attributes: createdAt : Date (with default value for today) title: String (with default value = Empty String)
Here is the code I have so far:
ContentView
import SwiftUI
struct ContentView: View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest(
entity: ToDoItem.entity(),
sortDescriptors: [
NSSortDescriptor(keyPath: \ToDoItem.createdAt, ascending: true),
NSSortDescriptor(keyPath: \ToDoItem.title, ascending: true)
]
) var toDoItems: FetchedResults<ToDoItem>
@State private var show_modal: Bool = false
var body: some View {
NavigationView {
List{
ForEach(toDoItems, id: \.self) {todoItem in
NavigationLink(destination: EditItemView(createdAt: todoItem.createdAt!, title: todoItem.title!)) {
ToDoItemView(title: todoItem.title!, createdAt: todoItem.createdAt!)
}
}
}
.navigationBarTitle(Text("My List"))
.navigationBarItems(trailing:
Button(action: {
self.show_modal = true
}) {
Text("Add")
}.sheet(isPresented: self.$show_modal) {
AddItemView().environment(\.managedObjectContext, self.managedObjectContext)
}
)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
return ContentView().environment(\.managedObjectContext, context)
}
}
AddItemView
import SwiftUI
struct AddItemView: View {
@Environment(\.presentationMode) var presentationMode
@Environment(\.managedObjectContext) var managedObjectContext
static let dateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
@State private var createdAt : Date = Date()
@State private var showDatePicker = false
@State private var title = ""
var body: some View {
NavigationView {
ScrollView {
HStack {
Button(action: {
self.showDatePicker.toggle()
}) {
Text("\(createdAt, formatter: Self.dateFormat)")
}
Spacer()
}
if self.showDatePicker {
DatePicker(
selection: $createdAt,
displayedComponents: .date,
label: { Text("Date") }
)
.labelsHidden()
}
TextField("to do item", text: $title)
.font(Font.system(size: 30))
Spacer()
}
.padding()
.navigationBarTitle(Text("Add transaction"))
.navigationBarItems(
leading:
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Cancel")
},
trailing:
Button(action: {
let toDoItem = ToDoItem(context: self.managedObjectContext)
toDoItem.createdAt = self.createdAt
toDoItem.title = self.title
do {
try self.managedObjectContext.save()
}catch{
print(error)
}
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Done")
}
)
}
}
}
struct AddItemView_Previews: PreviewProvider {
static var previews: some View {
AddItemView()
}
}
EditItemView
import SwiftUI
struct EditItemView: View {
@Environment(\.managedObjectContext) var managedObjectContext
static let dateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
var createdAt : Date
var title: String = ""
@State private var newCreatedAt : Date = Date()
@State private var showDatePicker = false
@State private var newTitle = ""
var body: some View {
ScrollView {
HStack {
Button(action: {
self.showDatePicker.toggle()
}) {
Text("\(createdAt, formatter: Self.dateFormat)")
}
Spacer()
}
if self.showDatePicker {
DatePicker(
selection: $newCreatedAt,
displayedComponents: .date,
label: { Text("Date") }
)
.labelsHidden()
}
TextField(title, text: $newTitle)
.font(Font.system(size: 30))
}
.padding()
.navigationBarTitle(Text("Edit transaction"))
.navigationBarItems(
trailing:
Button(action: {
print("Delete")
let deleteToDoItem = ToDoItem(context: self.managedObjectContext)
self.managedObjectContext.delete(deleteToDoItem)
do {
try self.managedObjectContext.save()
}catch{
print(error)
}
// let deleteToDoItem = self.toDoItems[indexSet.first!]
// self.managedObjectContext.delete(deleteToDoItem)
//
// do {
// try self.managedObjectContext.save()
// }catch{
// print(error)
// }
}) {
Text("Delete")
.foregroundColor(.red)
}
)
}
}
struct EditItemView_Previews: PreviewProvider {
static var previews: some View {
EditItemView(
createdAt: Date(),
title: "to do item"
)
}
}
ToDoItemView
import SwiftUI
struct ToDoItemView: View {
static let dateFormat: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
var title:String = ""
var createdAt:Date = Date()
var body: some View {
HStack{
VStack(alignment: .leading){
Text(title)
.font(.headline)
Text("\(createdAt, formatter: Self.dateFormat)")
.font(.caption)
}
}
}
}
struct ToDoItemView_Previews: PreviewProvider {
static var previews: some View {
ToDoItemView(title: "To do item", createdAt: Date())
}
}
P.s. I am aware that I can add .onDelete in list view. But I want to make it deliberately harder for the users to delete an item. This is why I want to move Delete button to details view.