Swift中动态/泛型数组实现:根据传入值确定数组类型
嘿,这个问题我之前做Picker封装的时候也纠结过,其实用Swift的泛型就能完美解决,根本不用碰[Any]那种容易踩坑的类型!下面给你一步步拆解实现方案:
用泛型实现类型自适应的UIPickerView数据源
核心思路是给自定义PickerView类加上泛型约束,让它的数据源数组能自动匹配传入的元素类型,同时保证编译时的类型安全。
第一步:定义泛型PickerView类
我们让泛型类型遵循Hashable(方便Picker做元素区分),同时实现Picker的数据源和代理方法:
import UIKit class CustomPickerView<T: Hashable>: UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate { // 泛型数组,自动适配传入的元素类型 var dataSourceArray: [T] = [] { didSet { // 数据源更新时自动刷新Picker reloadAllComponents() } } override init(frame: CGRect) { super.init(frame: frame) setupPicker() } required init?(coder: NSCoder) { super.init(coder: coder) setupPicker() } private func setupPicker() { dataSource = self delegate = self } // MARK: - Picker数据源&代理方法 func numberOfComponents(in pickerView: UIPickerView) -> Int { return 1 // 可根据你的需求调整组件数量 } func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { return dataSourceArray.count } func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { // 把泛型元素转成字符串显示,利用Swift的默认字符串转换 return "\(dataSourceArray[row])" } }
第二步:使用泛型PickerView
现在你可以直接传入不同类型的数组,编译器会自动推断泛型类型,完全不需要手动指定:
// 传入Int类型数组,此时dataSourceArray自动变成[Int] let intPicker = CustomPickerView(frame: CGRect(x: 0, y: 100, width: 300, height: 200)) intPicker.dataSourceArray = [1, 2, 3, 4, 5] // 传入String类型数组,此时dataSourceArray自动变成[String] let stringPicker = CustomPickerView(frame: CGRect(x: 0, y: 300, width: 300, height: 200)) stringPicker.dataSourceArray = ["Apple", "Banana", "Orange"] // 传入Double类型数组,此时dataSourceArray自动变成[Double] let doublePicker = CustomPickerView(frame: CGRect(x: 0, y: 500, width: 300, height: 200)) doublePicker.dataSourceArray = [1.5, 2.7, 3.9]
第三步:可选优化——限制允许的类型
如果希望只允许特定类型(比如String、Int、Double)被传入,可以自定义一个协议,让这些类型遵循它:
// 定义Picker兼容类型协议 protocol PickerCompatibleType: Hashable {} // 让需要的类型遵循协议 extension String: PickerCompatibleType {} extension Int: PickerCompatibleType {} extension Double: PickerCompatibleType {} // 修改泛型约束为自定义协议 class CustomPickerView<T: PickerCompatibleType>: UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate { // ... 其余代码不变 }
这样就能避免不符合要求的类型被传入,进一步提升代码安全性。
为什么这比[Any]好?
用泛型的核心优势是编译时类型检查,你在使用dataSourceArray时完全不需要强制类型转换:
// 直接获取选中的Int类型元素,没有转换失败风险 let selectedInt = intPicker.dataSourceArray[intPicker.selectedRow(inComponent: 0)] // 不需要写 let selectedInt = intPicker.dataSourceArray[...] as? Int 这种不安全的代码
彻底解决了类型转换带来的崩溃隐患,代码也更简洁易读。
内容的提问来源于stack exchange,提问作者Sohel L.
相关产品推荐
相关产品推荐

