简体   繁体   English

从 Picker 切换到 Image 视图会导致 SwiftUI 中的索引超出范围错误

[英]Toggling from Picker to Image view causes an index out of range error in SwiftUI

I have a view that uses a button to toggle between a Picker and an Image that is a result of the Picker selection.我有一个视图,它使用一个按钮在选择器和作为选择器选择结果的图像之间切换。 When quickly toggling from the image to the Picker and immediately back, I get a crash with the following error:当从图像快速切换到选择器并立即返回时,我遇到崩溃并出现以下错误:

Swift/ContiguousArrayBuffer.swift:600: Fatal error: Index out of range

Toggling less quickly doesn't cause this, nor does toggling in the other direction (picker to image and back).较慢地切换不会导致这种情况,也不会在另一个方向切换(选择器到图像并返回)。 Here is the offending code:这是有问题的代码:

import SwiftUI

struct ContentView: View {
    @State private var showingPicker = false
    @State private var currentNum = 0
    @State private var numbers: [Int] = [1, 2, 3, 4, 5]
    
    
    var body: some View {
        
            VStack(spacing: 15) {
                Spacer()
                if showingPicker {
                    Picker("Number", selection: $currentNum) {
                        ForEach(0..<numbers.count, id: \.self) {
                            Text("\($0)")
                        }
                    }
                    .pickerStyle(.wheel)
                } else {
                    Image(systemName: "\(currentNum).circle")
                }
                
                Spacer()
                
                Button("Toggle") {
                    showingPicker = !showingPicker
                }
                
            }
    }
}

The code works otherwise.代码以其他方式工作。 I'm new to SwiftUI so I'm still wrapping my head around how views are created/destroyed.我是 SwiftUI 的新手,所以我仍然在思考如何创建/销毁视图。 I tried changing the order of the properties thinking maybe the array was being accessed before it was recreated(if that's even something that happens) but that had no effect.我尝试更改属性的顺序,认为数组可能在重新创建之前被访问(如果发生这种情况),但这没有效果。 I also tried ForEach(numbers.indices) instead of ForEach(0..<numbers.count) , but it has the same result.我还尝试了ForEach(numbers.indices)而不是ForEach(0..<numbers.count) ,但结果相同。

**Edit **编辑

I figured out a stop-gap for now.我现在想出了一个权宜之计。 I added @State private var buttonEnabled = true and modified the button:我添加了@State private var buttonEnabled = true并修改了按钮:

Button("Toggle") {
    showingPicker = !showingPicker
    buttonEnabled = false
    DispatchQueue.main.asyncAfter(deadline: .now() + 0.35) {
        buttonEnabled = true
    }
}
.disabled(buttonEnabled == false)

To debounce it.去抖动它。 I still want to figure out the problem and make a real fix.我仍然想弄清楚问题并进行真正的修复。

**Edit **编辑

Based on comments I've modified the code to take array indexing out of the equation and to better reflect the actual project I'm working on.根据评论,我修改了代码,将数组索引排除在等式之外,以更好地反映我正在从事的实际项目。 The code still works, but a quick toggle will cause the exact same crash and error.该代码仍然有效,但快速切换将导致完全相同的崩溃和错误。 It also seems to only happen when the.wheel style picker is used, other picker styles don't have this behavior.它似乎也只发生在使用 .wheel 风格的选择器时,其他选择器 styles 没有这种行为。

private let icons = ["ear", "cube", "eye", "forward", "gear"]

struct ContentView: View {
    @State private var showingPicker = false
    @State private var currentIcon = icons[0]
    
    var body: some View {
        VStack(spacing: 15) {
            Spacer()
            if showingPicker {
                Picker("Icon", selection: $currentIcon) {
                    ForEach(icons, id: \.self) {
                        Image(systemName: $0)
                    }
                }
                .pickerStyle(.wheel)
            } else {
                Image(systemName: currentIcon)
            }
            
            Spacer()
            
            Button("Toggle") {
                showingPicker.toggle()
            }
        }
    }
}

ForEach is not a for loop, you can't use array.count and id:\.self you need to use a real id param or use the Identifiable protocol. ForEach 不是 for 循环,您不能使用array.countid:\.self您需要使用真实的 id 参数或使用Identifiable协议。

However if you just need numbers it also supports this:但是,如果您只需要数字,它也支持:

ForEach(0..<5) { i in

As long as you don't try to look up an array using i .只要您不尝试使用i查找数组。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM