Search code examples
swiftswiftuiios14xcode12

Pass an observed object's projected value's property to @Binding


I have a main screen with an @FetchRequest that returns a FetchResult<Item>. In that main screen I have a list of all of the items with navigation links that, when selected, pass an Item to an ItemDetail view. In this ItemDetail view, item is marked with @ObservedObject. A subview of ItemDetail is ItemPropertiesView which lists all of the item's properties. I pass the item properties directly to @Binding properties of ItemPropertiesView using $item.{insert property here}. In ItemPropertiesView, there's several LineItem where I pass the property using $ once again to an @Binding property called "value" which is passed into a text field, that can ultimately be changed.

My goal is to be able to edit this text field and once you're done editing, to be able to save these changes to my core data store.

Since this has been a little hard to read, here is a code recreation:

struct MainScreen: View {
    @FetchRequest(entity: Item.entity(), sortDescriptors: [NSSortDescriptor(key: "itemName", ascending: true)]) var items: FetchedResults<Item>
    var body: some View {
        NavigationView {
            List {
                ForEach(items, id: \.self) { (item: Item) in
                    NavigationLink(destination: ItemDetail(item: item)) {
                        Text(item.itemName ?? "Unknown Item Name")
                    }
                } // ForEach
            }
        }
    } // body
} // MainScreen

struct ItemDetail: View {
    @ObservedObject var item: Item

    var body: some View {
        ItemPropertiesView(itemCost: $item.itemCost)
    }
}

struct ItemPropertiesView: View {
    @Binding var itemCost: String?

    var body: some View {
        LineItem(identifier: "Item Cost", value: $itemCost)
    }
}

struct LineItem: View {
    let identifier: String
    @Binding var value: String

    var body: some View {
        HStack {
            Text(identifier).bold() + Text(": ")
            TextField("Enter value",text: $value)
        }
    }
}

I am getting an error in ItemDetail: "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions"

This is on the only error I'm getting. I'm new to SwiftUI, so all feedback is appreciated.


Solution

  • Just by code reading I assume the problem is in optional property in ItemPropertiesView, just remove it

    struct ItemPropertiesView: View {
        @Binding var itemCost: String      // << here !!
        // .. other code
    

    and update parent to have bridge to CoreData model optional property

    struct ItemDetail: View {
        @ObservedObject var item: Item
    
        var body: some View {
            let binding = Binding(
                get: { self.item.itemCost ?? "" },
                set: { self.item.itemCost = $0 }
            )
            return ItemPropertiesView(itemCost: binding)
        }
    }