SwiftUI: Updating an array item does not update the child UI immediately

て烟熏妆下的殇ゞ 提交于 2021-01-01 04:24:29

问题


I have an array of items (numbers) to be presented to the user using NavigationView, List and a leaf page.

When I update an item (numbers[index] = ...) on a leaf page, it updates the list correctly (which I see when I go back to the list), but not the leaf page itself immediately. I see the change if I go back to the list and re-open the same leaf page.

I would like to understand why it does not update the UI immediately, and how to fix it. Here is the simplified code to re-produce this behavior.

ADDITIONAL INFORMATION This code works fine on Xcode 12. It fails only on Xcode 12.1 (RC1) and Xcode 12.2 (beta3).

import SwiftUI

struct NumberHolder: Identifiable {
    let id = UUID()
    let value:Int
}

struct Playground: View {
    @State var numbers:[NumberHolder] = [
        NumberHolder(value:1),
        NumberHolder(value:2),
        NumberHolder(value:3),
        NumberHolder(value:4),
    ]
    var body: some View {
        NavigationView {
            List(numbers.indices) { index in
                let number = numbers[index]
                NavigationLink(destination: VStack {
                    Text("Number: \(number.value)")
                    Button("Increment") {
                        numbers[index] = NumberHolder(value: number.value + 1)
                    }
                } ) {
                    Text("Number: \(number.value)")
                }
            }
        }
    }
}

struct Playground_Previews: PreviewProvider {
    static var previews: some View {
        Playground()
    }
}

回答1:


This had me scratching my day for a few weeks.

It appears there are many features within SwiftUI that do not work in Views that are placed in Lists directly, however if you add a ForEach inside the List said features (such as .listRowPlatterColor(.green) on WatchOS) start to work.

Solution

On iOS 14.2 if you wrap the NavigationLink inside a ForEach the NavigationLink destination (leaf page) will update right away when the data model is updated.

So change your code to

var body: some View {
        NavigationView {
            List {
                ForEach(numbers.indices) { index in
                    let number = numbers[index]
                    NavigationLink(destination: VStack {
                        Text("Number: \(number.value)")
                        Button("Increment") {
                            numbers[index] = NumberHolder(value: number.value + 1)
                        }
                    } ) {
                        Text("Number: \(number.value)")
                    }
                }
            }
        }
    }

Frustratingly, this does not solve the issue when using WatchOS, in WatchOS 7.0 the leaf page is updated, however in WatchOS 7.1 (version goes hand in hand with iOS 14.2 that suffered this "issue") so I have an issue open with Apple FB8892330

Further frustratingly, I still don't know if this is a bug or a feature in SwiftUI, none of the documentation state the requirement for ForEach inside of Lists




回答2:


Try this one. I tested and it works.

import SwiftUI

struct NumberHolder: Identifiable {
    let id = UUID()
    let value:Int
}

struct ContentView: View {   
    @State var numbers:[NumberHolder] = [
        NumberHolder(value:1),
        NumberHolder(value:2),
        NumberHolder(value:3),
        NumberHolder(value:4),
    ]
    var body: some View {
        NavigationView {
            List(numbers.indices) { index in
                NavigationLink(destination: DetailView(numbers: $numbers, index: index)) {
                    Text("Number: \(self.numbers[index].value)")
                }
            }
        }
    }
}

struct DetailView: View {
    @Binding var numbers:[NumberHolder]
    let index: Int
    
    var body: some View {
        VStack {
            Text("Number: \(self.numbers[index].value)")
            
            Button("Increment") {
                numbers[index] = NumberHolder(value: numbers[index].value + 1)
            }
        }
    }
}



回答3:


I found the answer. It was a bug in Xcode. This code (without any changes) works fine under Xcode 12.0, but fails to update under Xcode 12.2 beta 2.



来源:https://stackoverflow.com/questions/64611300/swiftui-updating-an-array-item-does-not-update-the-child-ui-immediately

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!