SwiftUI Stepper组件导航至最后项时触发数组越界致命错误求助
问题分析与解决方案
崩溃根因
你遇到的Fatal error: Index out of range,是因为updateTimer方法里直接用newValue访问steps[newValue]时,newValue超出了数组的有效索引范围。当导航到最后一项时,selected的值可能被设置为等于steps.count(比如你说的6个值,数组索引是0-5,此时selected变成6),直接访问steps[6]自然触发越界崩溃。
修复方案
1. 先做索引合法性校验
在updateTimer开头添加索引范围检查,避免越界访问:
func updateTimer(newValue: Int) { timer?.invalidate() // 先确保newValue在数组有效索引内 guard newValue >= 0, newValue < steps.count else { return } guard case .animated(let duration) = steps[newValue] else { return } timer = Timer.scheduledTimer(withTimeInterval: Double(duration), repeats: false, block: { _ in // 替换成更清晰的判断逻辑 if selected < steps.count - 1 { withAnimation { selected += 1 } } }) }
2. 从根源限制selected的取值范围
在初始化方法里给selected的绑定值加一层包装,确保它永远不会超出数组索引范围:
public init(selected: Binding<Int>, steps: [Step]) { // 初始化时修正越界的selected值 let clampedValue = min(max(selected.wrappedValue, 0), steps.count - 1) // 包装绑定,后续任何修改都会被限制在合法范围内 self._selected = Binding( get: { clampedValue }, set: { selected.wrappedValue = min(max($0, 0), steps.count - 1) } ) self.steps = steps }
3. 优化定时器触发判断
原代码里的steps.count > selected + 1等价于selected < steps.count -1,后者语义更直观,建议替换避免逻辑混淆。
调试建议
崩溃时可以在updateTimer开头打印newValue和steps.count的具体数值,确认触发越界时的参数状态,方便进一步排查是否有其他逻辑在修改selected的值。
内容的提问来源于stack exchange,提问作者Sullivan
相关产品推荐
相关产品推荐

