Learn Courses My Dashboard

SwiftUI Edit Item Data Using CoreData

Hi,

I have gotten stuck and have not found an answer after hours of looking. I am using CoreData and viewing the details of an item from a list. Then I want to be able to edit the details. When I try to pass the item data from the detail view to an edit item view I get the error “Cannot invoke initializer for type ‘DetailView’ with an argument list of type ‘(myItem: Item)’” in the preview section. I think I am not passing the data to the next view correctly in EditItemView(name: self.$name), but I really am not sure. Maybe I am just not understanding what I need to add to the preview section. The preview was fine until I tried to pass the data to the Edit Item View. Below is the code for the Detail View that the user can see the item they selected in the list, and then code for the Edit Item View where they should be able to edit the data. Any help would be greatly appreciated.

Detail View:

import CoreData
import SwiftUI

struct DetailView: View {
    @Environment(\.managedObjectContext) var moc
    @ObservedObject var myItem: Item
    
    @State private var name: String
    @State private var showingEditScreen = false
    
    var body: some View {
        NavigationView {
            VStack {
                Text(self.myItem.name ?? "Unknown Item")
                Text(self.myItem.attribute ?? "Unknown attribute")
            }
        }
        .navigationBarTitle(Text(myItem.name ?? "Unknown Item"), displayMode: .inline)
        .navigationBarItems(trailing:
            Button(action: {
                self.showingEditScreen.toggle()
            }) {
                Image(systemName: "square.and.pencil")
            }
        )
        .sheet(isPresented: $showingEditScreen) {
            EditItemView(name: self.$name).environment(\.managedObjectContext, self.moc)
        }
    }
}

struct DetailView_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

    static var previews: some View {
        let item = Item(context: moc)
        item.name = "Test item"
        item.attribute = "Test attribute"

        return NavigationView {
            DetailView(myItem: item)
        }
    }
}

Edit Item View:

import SwiftUI

struct EditItemView: View {
    @Environment(\.managedObjectContext) var moc
    
    @Binding var name: String
    
    var body: some View {
        TextField("Enter Item Name", text: $name)
    }
}

struct EditItemView_Previews: PreviewProvider {
    static var previews: some View {
        EditItemView(name: .constant("ItemX"))
    }
}

I figured it out. It was all in how I was trying to pass the data. Had to setup a new @ObservedObject in the EditItemView and use that name in the DetailView. Updated view codes below. Now the data is passed to the EditItemView.

DetailView:

import CoreData
import SwiftUI

struct DetailView: View {
    @Environment(\.managedObjectContext) var moc
    @ObservedObject var myItem: Item
    
    @State private var showingEditScreen = false
    
    var body: some View {
        NavigationView {
            VStack {
                Text(self.myItem.name ?? "Unknown name")
                Text(self.myItem.attribute ?? "Unknown attribute")
            }
        }
        .navigationBarTitle(Text(myItem.name ?? "Unknown Item"), displayMode: .inline)
        .navigationBarItems(trailing:
            Button(action: {
                self.showingEditScreen.toggle()
            }) {
                Text("Edit")
            }
        )
        .sheet(isPresented: $showingEditScreen) {
            EditItemView(editItem: self.myItem).environment(\.managedObjectContext, self.moc)
        }
    }
}

struct DetailView_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)

    static var previews: some View {
        let item = Item(context: moc)
        item.name = "Test item"
        item.attribute = "Test attribute"

        return NavigationView {
            DetailView(myItem: item)
        }
    }
}

EditItemView:

import SwiftUI

struct EditItemView: View {
    @Environment(\.managedObjectContext) var moc
    @ObservedObject var editItem: Item
    
    var body: some View {
       Text(self.editItem.name ?? "Unknown name")
    }
}

struct EditItemView_Previews: PreviewProvider {
    static let moc = NSManagedObjectContext(concurrencyType: .mainQueueConcurrencyType)
    
    static var previews: some View {
        let item = Item(context: moc)
        item.name = "Test item"
        
        return NavigationView {
            EditItemView(editItem: item)
        }

    }
}