我有一个全局数组:
let genderList = ["Not Selected", "Woman", "Man", "Non Binary", "Trans", "Would rather not say"]
结构实例变量:
@State var selectedGender = genderList[0]
我的视图中有一个选择器:
Picker("Please select your gender", selection: $selectedGender) {
ForEach(genderList, id: \.self) {
Text($0)
}
}.pickerStyle(.wheel)
对于我的生活,我似乎无法理解为什么会引发以下错误:
Swift/ContiguousArrayBuffer.swift:600: 致命错误:索引超出范围
我也试过类似的错误:
Picker("", selection: $selectedGender) {
ForEach(genderList.indices, id: \.self) { index in
Text(genderList[index])
}
}.pickerStyle(.wheel)
任何帮助将不胜感激。 谢谢
超出范围的索引来自硬索引访问:
@State var selectedGender = genderList[0]
这里是一些测试代码证明。 State 变量初始化导致访问索引 [0],这是对索引的唯一硬访问,并且必须看到索引错误。在测试代码中,设置该全局值的任何延迟(甚至 .now() - 无延迟)都会导致索引外崩溃。即使对主线程异步队列进行更新也会导致视图初始化尝试初始化状态,即。数组 [0],并超出范围崩溃。
在一个单一视图的简单测试场景中,这太快了,你在比赛中“走运”,没有发现问题。在我的测试中工作。使用下面的代码,它显示了具有成员(即 [0] 是有效索引)的全局 var 数组中的任何延迟都会导致索引超出范围。
正如我在之前的一些评论中提到的,我在针对应用程序加载场景运行工具的经验中,swiftui 似乎确实是多线程初始视图构建,期望每个视图定义/状态初始化都是线程安全的(即自包含并且不访问异步或变量取决于具体的代码运行顺序)。访问全局数组 var 的索引不是线程安全的。
在一个非常小的视图层次结构中,大多数时候你“侥幸逃脱”,因为它运行得如此之快,而且通常是单线程的简单视图。我希望海报应用程序具有更复杂的层次结构,或者存在其他处理延迟,因此存在竞争。
一个简单的测试是将 State 直接设置为常量而不是访问数组。如果它有效,它的初始化 = [0] 即索引超出建议的范围。
注意视图已构建,状态尝试初始化并命中超出范围的索引。将性别列表设置为一个值,一切都很好。
let genderList: [String] = {
print("Trying to set the gloabl var.....")
var value: [String] = []
let result = DispatchQueue.main.asyncAfter(deadline: (.now() )) {
print("Setting VAR")
value = ["Not Selected", "Woman", "Man", "Non Binary", "Trans", "Would rather not say"]
}
return value
}()
struct ContentView: View {
@State var selectedGender = genderList[0] {
didSet {
print("State Initialised")
}
}
var body: some View {
print("View Body Evaulatued")
return VStack {
Text("Selected: \(selectedGender) ")
Picker("Please select your gender", selection: $selectedGender) {
ForEach(genderList, id: \.self) {
Text($0)
}
}.pickerStyle(.wheel)
}
}
}
问题不在于选择器。