取消选择 SwiftUI 列表中的项目会使应用程序崩溃

Unselecting an item on a SwiftUI list crashes the app

我在使用带有可选绑定的 SwiftUI 时遇到问题,基本上它是 macOS 上的一个列表,一旦某个项目被 selected,我就会在其中添加一个 DetailView,如果不是 selected 就添加一个文本。

当我打开应用程序时它很好,文本出现,然后我添加了一些项目和 select 它,也工作正常,DetailView 出现,但是一旦我在 table 之外单击,un select它崩溃了。即使很艰难,我也有条件检查 nil,这就是它第一次起作用的原因。

我猜 DetailView 保留了对 selectedItem 的引用,一旦它设置为 nil 就会崩溃,但我认为一旦 State 属性 改变,整个主体都应该刷新,这会从内存中删除之前的 DetailView 而不是调用新的,对吗?

代码如下:

import SwiftUI

struct DetailView: View {
    @Binding var text: String

    var body: some View {
        TextField("123", text: self.$text)
    }
}

struct ContentView: View {
    @State var text = ""
    @State var items = [String]()
    @State var selectedItem: String? = nil

    var body: some View {
        VStack {
            HStack {
                VStack(alignment: .leading, spacing: 0) {
                    List(selection: $selectedItem) {
                        ForEach(items, id: \.self) { item in
                            Text(item)
                        }
                    }
                    HStack(spacing: 0) {
                        Button(action: {
                            self.items.append(UUID().uuidString)
                        }, label: {
                            Text("Add")
                        })
                        Button(action: {
                            if let item = self.selectedItem {
                                self.items.remove(at: self.items.firstIndex(of: item)!)
                            }
                            self.selectedItem = nil
                        }, label: {
                            Text("Remove")
                        }).disabled(selectedItem == nil)
                    }
                }
                if selectedItem != nil {
                    DetailView(text: Binding($selectedItem)!)
                } else {
                    Text("Add an item")
                }
            }
            .tabItem {
                Text("Test")
            }
        }.frame(maxWidth: .infinity, maxHeight: .infinity)
    }
}

I guess the DetailView is keeping a reference to the selectedItem and crashing once it’s set to nil, but I thought the entire body should be refreshed once a State property is changed, which would remove the previous DetailView from memory and not call a new one, right?

没有定义更新的顺序,所以我在上面回答否。

这是一个解决方案。使用 Xcode 11.4 / iOS 13.4

测试
if selectedItem != nil {
    DetailView(text: Binding(get: {self.selectedItem ?? ""}, 
                             set: {self.selectedItem = [=10=]}))
} else {
    Text("Add an item")
}