在带有macOS
和iPadOS
的SwiftUI上,当我使NavigationLink
项的数量可变然后尝试删除最后一个项时,我崩溃了。删除除最后一项以外的其他所有项都很好。崩溃时,我得到了日志打印:
Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift, line 444
似乎destination
中的NavigationLink
比NavigationLink
本身的生存时间更长,这在短时间内给destination
带来了无效的绑定。仅当destination
需要Binding
(例如,能够编辑某些内容)时,才会显示崩溃。如果我将Text
的视图用作destination
而不是TextField
,则不会崩溃。
这是一个复制的最小示例:
import SwiftUI
struct ContentView: View {
@State var strings = ["Hello World 1", "Hello World 2", "Hello World 3"]
@State var selectedStringIndex: Int?
var body: some View {
NavigationView {
VStack {
Button("Remove Selected") { // when removing the last element => crash
if let selectedStringIndex = selectedStringIndex {
strings.remove(at: selectedStringIndex)
}
}
List(strings.indices, id: \.self, selection: $selectedStringIndex) { stringIndex in
NavigationLink(destination: TextField("Name", text: $strings[stringIndex]),
tag: stringIndex, selection: $selectedStringIndex) {
Text(strings[stringIndex])
}
}
}
}
}
}
处理NavigationLink
个项目的动态数量的推荐方法是什么?
我在Xcode 12.2 beta 4
上使用macOS 11.0.1 Beta
答案 0 :(得分:1)
一种可行的解决方案是使用自定义Binding
并检查index
是否在范围内 :
func binding(for index: Int) -> Binding<String> {
.init(get: {
guard strings.indices.contains(index) else { return "" } // check if `index` is valid
return strings[index]
}, set: {
strings[index] = $0
})
}
然后,您可以在NavigationLink
中使用此绑定:
NavigationLink(destination: TextField("Name", text: binding(for: stringIndex)), ...)
还要确保删除后重置selectedStringIndex
:
Button("Remove Selected") {
if let selectedStringIndex = selectedStringIndex {
strings.remove(at: selectedStringIndex)
self.selectedStringIndex = nil // reset here
}
}