SwiftUI view not updated after SwiftData change through CloudKit

A SwiftUI view is displaying a SwiftData model object that's being updated on another device, using CloudKit. The update arrives through CloudKit and the view is correctly updated. However, when the view is not displaying the model object directly, but in a nested view, this nested view is NOT updated. Why not? Is this a bug? Or is it just me, forgetting about some elementary detail?

A workaround (that I definitely don't like!) is to put a dummy SwiftData query in the nested view. Even when the dummy query result is never used, the view now IS updated correctly. Why?

The code below is mostly Xcode's standard template for a SwiftUI+SwiftData+CloudKit app, modified to use a String property i.s.o. a Date, and to be able to edit that name in a Textfield.

The ContentView:

struct ContentView: View {
    @Environment(\.modelContext) private var modelContext
    @Query private var items: [Item]
    
    var body: some View {
        NavigationSplitView {
            List {
                ForEach(items) { item in
                    @Bindable var item = item
                    NavigationLink {
                        VStack(alignment: .leading) {
                            
                            // item details in same view
                            TextField(item.name, text: $item.name)
                                .textFieldStyle(.roundedBorder)
                                .padding()
                                .background(.red.opacity(0.5))
                            
                            // item details in nested view
                            ItemDetailView(item: item)
                                .padding()
                                .background(.yellow.opacity(0.5))
                            
                            Spacer()
                        }
                    } label: {
                        Text(item.name)
                    }
                }
                .onDelete(perform: deleteItems)
            }
#if os(macOS)
            .navigationSplitViewColumnWidth(min: 180, ideal: 200)
#endif
            .toolbar {
#if os(iOS)
                ToolbarItem(placement: .navigationBarTrailing) {
                    EditButton()
                }
#endif
                ToolbarItem {
                    Button(action: addItem) {
                        Label("Add Item", systemImage: "plus")
                    }
                }
            }
        } detail: {
            Text("Select an item")
        }
    }
    
    private func addItem() {
        withAnimation {
            let newItem = Item(name: "item")
            modelContext.insert(newItem)
        }
    }
    
    private func deleteItems(offsets: IndexSet) {
        withAnimation {
            for index in offsets {
                modelContext.delete(items[index])
            }
        }
    }
}

The nested ItemDetailView:

struct ItemDetailView: View {
    
    @Bindable var item: Item
    
    // dummy query to force view updates triggered by CloudKit
//  @Query private var items: [Item]
    
    var body: some View {
        TextField(item.name, text: $item.name)
            .textFieldStyle(.roundedBorder)
    }
}

The result:

@effenix Have you able to resolve your issue? Having the same one, here is the example:

struct ContentView: View {
    @Query(sort: \File.name) private var files: [File]

    var body: some View {
        NavigationStack {
            FilesView(files: files) // <- Just wrapped the code into a separate view
        }
    }
}

struct FilesView: View {
    var files: [File]

    var body: some View {
        ForEach(files) { file in
            NavigationLink(value: file) {
                FileTileView(file: file) // <- Another extracted view
            }
        }
    }
}

struct FileTileView: View {
    var file: File

    var body: some View {
        Text(file.name) // <- Doesn't get updated when CloudKit received the sync update
    }
}

It does work without the wrappers:

@Model
final class File {
    var name: String = "" // <- I edit the name on another device in the simple text editor, the editor code is ommited as it's not significant

    init(name: String) {
        self.name = name
    }
}

struct ContentView: View {
    @Query(sort: \File.name) private var files: [File]

    var body: some View {
        NavigationStack {
            ForEach(files) { file in
                NavigationLink(value: file) {
                    Text(file.name) // <- The text updates successfully after CloudKit sync
                }
            }
        }
    }
}

Having the same problem on iOS 17.4

I'm having this problem as well. This is potentially a major issue.

SwiftUI view not updated after SwiftData change through CloudKit
 
 
Q