0

Please excuse me if I'm using the wrong nomenclature of things, but this is the first time I'm using CoreData. I'm editing text in one of the items stored using CoreData. The way it works on the app is when tapping on an item in a list, a sheet pops up with the text that is already there, and if changed, saves the new text.

I'm struggling with how to pass the correct item to the sheet, and then how to update the correct item. How do you do this? I'm not sure how passing data works.

Here's what I worked out so far:

struct ContentView: View {

    @FetchRequest(entity: Jot.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Jot.date, ascending: false)])
    var jots: FetchedResults<Jot>

    @State var selectedJot: Jot
    @State var isNew = false

    var body: some View {
        NavigationView {
            List(jots) { jot in
                Text(jot.text ?? "")
                .onTapGesture() {
                    self.selectedJot = jot
                    isNew = false
                }
            }
            .listStyle(.plain)
            .toolbar {
                ToolbarItem(placement: .bottomBar) {
                    Spacer()
                }
                
                ToolbarItem(placement: .bottomBar) {
                    Button(action: {
                        isNew = true
                        self.sheetNewNote.toggle()
                        selectedItem = 0
                    }) {
                        Image(systemName: "square.and.pencil")
                    }
                }
            }
            .sheet(item: $selectedJot) { jot in
                SheetView(isNewItem: $isNew, currJot: self.$selectedJot) // I get error Cannot convert value of type 'Binding<Jot>' to expected argument type 'Binding<Item?>'
            }
            .sheet(isPresented: $sheetNewNote) {
                    SheetView(isNewItem: $isNew, currJot: self.$selectedJot) // no error here
            }
        }
    }


    struct SheetView: View {
        @Environment(\.presentationMode) var presentationMode
        
        @Binding var isNewItem: Bool
        @Binding var currJot: Jot

        @State var text: String = ""

        var body: some View {
            NavigationView {
                 VStack {
                    TextEditor(text: $text)
                    .onAppear() {
                        if isNewItem {
                            text = currJot.text!
                        }
                    }
                    HStack {
                        Button("Cancel") {
                            presentationMode.wrappedValue.dismiss()
                        }

                        Spacer()

                        Button("Save") {
                            if isNewItem {
                                // create a new item and save it with try viewContext.save()
                            } else {
                                // we are editing a current item
                                updateJot(updatedJot: currJot)
                                try? viewContext.save()
                            }

                            presentationMode.wrappedValue.dismiss()
                        }
                    }
                 }
            }
        }


        // Updates the item
        func updateJot(updatedJot: Jot){
            if let jot = getById(id: updatedJot.objectID){
                jot.text = updatedJot.text
            }
        }
        
        // Gets a item by id
        func getById(id: NSManagedObjectID) -> Jot? {
            return viewContext.object(with: id) as? Jot
        }

    }
}

EDIT:

trying to understand more about how CoreData and SwiftUI work. Based on the comment below, I should use @ObservableObject but when I went looking for more information, I couldn't find any definitive examples. This article also made even more confusing to me.

So, question still: how so I update an item already existing via a sheet?

This, however, looks promising... I just need to understand what they did and see if I can replicate it on my code.

Aleph
  • 465
  • 2
  • 12
  • All CoreData objects are `ObservableObject`s you should use `@ObservedObject` instead of `@Binding` – lorem ipsum Apr 27 '22 at 21:37
  • Do I use them as a variable? – Aleph Apr 27 '22 at 21:45
  • I converted `@Binding` to `@ObservedObject`. Still trying to figure out why `SheetView(isNewItem: $isNew, currJot: $selectedJot)` gets a `Cannot convert value of type 'Binding' to expected argument type 'Jot'` – Aleph Apr 27 '22 at 21:58
  • @loremipsum this looks promising, but I need to figure how do apply this to my code: https://stackoverflow.com/questions/62804190/swiftui-update-view-on-core-data-object-change – Aleph Apr 27 '22 at 22:16
  • Remove the dollar sign for the sheet it isn’t a Binding. Binding is for value type not references. – lorem ipsum Apr 27 '22 at 22:21
  • @loremipsum already tried that, and the `Value of optional type 'Jot?' must be unwrapped to a value of type 'Jot'`, which it doesn't matter what I do, fails on nil. Any chance you could post a small sample code? I tried with `@State private var selectedJot: Jot? = nil` or any kind of variations in ContentView. I simply don't know what I'm doing. – Aleph Apr 27 '22 at 22:27
  • 1
    Use jot not selectedJot. The one that the sheet gives you that isn’t optional. – lorem ipsum Apr 27 '22 at 22:31
  • Got it, @loremipsum, thanks. What about the presentation of the sheet for new items? Right now I'm calling it as `.sheet(isPresented: $sheetNewNote) { SheetView(isNewItem: $isNew, currJot: selectedJot) }` – Aleph Apr 27 '22 at 22:33
  • You can’t have 2 sheets in one view get rid one and assign the new object to selectedJot – lorem ipsum Apr 27 '22 at 22:35
  • Sorry, I'm confused, how am I supposed to call the sheet upon creating a new item? @loremipsum – Aleph Apr 27 '22 at 22:36
  • Just like you do in the onTapGesture except with a new object. – lorem ipsum Apr 27 '22 at 22:38
  • @loremipsum OK. I have no idea what you are talking about, and also passing `jot` is causing the change not to be saved. I'm stuck again. A simple sample code would go a long way, but thank you for the help anyway, it was informative. – Aleph Apr 27 '22 at 22:43
  • People ask this exact question at least once a week on here. You can find plenty of answers. You are over complicating something very simple those methods you have updating and getting are unnecessary. All you have to do is make the changes and save the context. Look at the sample code apple gives with a new project that is all you need for this. – lorem ipsum Apr 27 '22 at 22:47

0 Answers0