You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:49:22