16

I'm trying to edit an item in a separate detail view. I want to have the item details populated inside a textfield after selecting the item from the list.

      List {
                    ForEach(vm.savedEntites) { entity in
                        Text(entity.name ?? "No Name")

                        HStack {
                        Button(action: {vm.deleteMemory(entity: entity)}) {
                                       Label("Delete",systemImage: "trash")
       
                                     }
                     
                            Button(action: {
                                    vm.selectedEntity = entity
                                    showingDetailScreen.toggle()}) {
                            Label("Details", systemImage: "pencil")
                                     }
                            
                        }
                    }// list ends here
                    .sheet(isPresented: $showingDetailScreen) {
                        DetailItemView(isVisible: self.$showingDetailScreen, entity: vm.selectedEntity!, text: vm.selectedEntity!)
                           }// sheet ends here
                }
            

The detail item view sheet. This is where i'm getting this error next to TextField

Cannot convert value of type 'Binding<String?>' to expected argument type 'Binding'

 struct DetailItemView: View  {
        
        @Environment(\.presentationMode) var presentationMode
        @Binding var isVisible: Bool
        var entity: MemoryEntity
        @ObservedObject var text: MemoryEntity
 
        var body: some View {
           Text(entity.name ?? "No Name")
           TextField(text.name ?? "No Name", text: $text.name)
         ....}

This is the CoreData model class for items

class CoreDataViewModel: ObservableObject {
    let container: NSPersistentContainer
    @Published var savedEntites: [MemoryEntity] = []
    @Published var selectedEntity: MemoryEntity?
    init() {
        container = NSPersistentContainer(name: "MemoryContainer")
        container.loadPersistentStores { (description, error) in
            if let error = error {
              print("Error loading CoreData. \(error)")
        }
        }
        FetchMemories()
    }
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
swiftnoob
  • 303
  • 1
  • 5
  • 21

1 Answers1

50

Because all core data fields are optional, you have to wrap it into Binding. And as you're using core data and may face a lot of optionals, you can create an extension:

extension Binding {
     func toUnwrapped<T>(defaultValue: T) -> Binding<T> where Value == Optional<T>  {
        Binding<T>(get: { self.wrappedValue ?? defaultValue }, set: { self.wrappedValue = $0 })
    }
}

Use it like this:

TextField("title", text: $text.name.toUnwrapped(defaultValue: ""))
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220
  • Nice workaround however in many cases you need to keep it optional to avoid setting value – Hamad Fuad Mar 04 '22 at 06:37
  • For future reference, Jim Dovey wrote a nice article about this: https://alanquatermain.me/programming/swiftui/2019-11-15-CoreData-and-bindings/ – kafran Oct 21 '22 at 23:54