iOS Swift 5.1下UIPickerView数组越界致命错误的解决方法
解决UIPickerView的“Index out of range”错误
咱们先来定位问题的根源:你遇到的数组越界错误,核心是在numberOfRowsInComponent方法中直接访问pShipmentCategories[selected]时,pShipmentCategories的长度可能小于等于selected的值,或者对应索引的元素根本不存在。
为什么会出现这个情况?
从你的调试信息和接口数据来看,大概率是异步请求的时序问题:
- 你已经成功获取到计划日期数据,
pPlandateCategories有值,但运单数据是依赖计划日期的异步请求,当UIPickerView第一次加载时,pShipmentCategories可能还没被填充数据,甚至连和pPlandateCategories匹配的空数组结构都没有。 - 比如
pPlandateCategories有2个元素,但pShipmentCategories是空数组,这时候selected=0访问pShipmentCategories[0]自然会触发越界错误。
具体修复方案
1. 先对齐pShipmentCategories的结构
当你拿到计划日期数据后,先初始化pShipmentCategories为对应数量的空数组,确保它的长度和pPlandateCategories完全匹配:
// 解析计划日期接口返回后执行 pPlandateCategories = ["20190826", "20190827"] // 初始化对应数量的空数组,避免后续索引访问失败 pShipmentCategories = Array(repeating: [String](), count: pPlandateCategories.count)
2. 在所有数组访问前加安全判断
修改PickerView的几个核心方法,添加索引有效性检查,彻底避免越界:
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { if component == 0 { return pPlandateCategories.count } else { let selected = pickerView.selectedRow(inComponent: 0) // 先判断selected是否在有效索引范围内 guard selected < pShipmentCategories.count else { return 0 } return pShipmentCategories[selected].count } } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { if component == 0 { guard row < pPlandateCategories.count else { return nil } return pPlandateCategories[row] } else { let selected = pickerView.selectedRow(inComponent: 0) // 双重安全校验:先校验日期索引,再校验运单行索引 guard selected < pShipmentCategories.count, row < pShipmentCategories[selected].count else { return nil } return pShipmentCategories[selected][row] } } func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { if component == 0 { pickerView.reloadComponent(1) } else { let selected = pickerView.selectedRow(inComponent: 0) guard selected < pShipmentCategories.count, row < pShipmentCategories[selected].count else { someTextField.text = "Shipment: N/A" return } someTextField.text = "Shipment:" + " " + pShipmentCategories[selected][row] } }
3. 运单数据加载完成后刷新PickerView
当你获取到某一天的运单数据后,更新pShipmentCategories对应位置的数组,再刷新第二个组件:
// 解析20190827的运单数据后执行 if let dateIndex = pPlandateCategories.firstIndex(of: "20190827") { pShipmentCategories[dateIndex] = ["4505023244", "4505023274"] yourPickerView.reloadComponent(1) }
这样就能从根源上避免数组越界的问题啦。
内容的提问来源于stack exchange,提问作者Developper
相关产品推荐
相关产品推荐

