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

UIAlertController内嵌UITableView移入独立类后无法加载数据问题

解决UITableView在UIAlertController中不显示行的问题

你遇到的问题主要有两个核心原因,我帮你逐一梳理并给出修复方案:

1. 未禁用UITableView的自动约束转换

当使用Auto Layout给视图添加自定义约束时,必须将视图的translatesAutoresizingMaskIntoConstraints属性设为false。否则系统会根据你初始化时的frame自动生成默认约束,这会和你手动添加的约束产生冲突,最终导致UITableView被压缩到没有高度——虽然numberOfRowsInSection返回了正确的行数,但因为tableView本身不可见,系统不会触发cellForRowAt方法。

2. 未正确传递数据源到ListPicker实例

你的showListPicker方法接收了items参数,但没有把它赋值给类的self.items属性。这会导致tableView(_:numberOfRowsInSection:)方法中items?.count实际为nil(除非你在外部提前给ListPicker的items属性赋值,但这不符合封装逻辑),即使你认为返回了正确行数,也可能是测试时的偶然情况。

修改后的完整代码

我标注了关键修改点,同时做了一些体验优化:

class ListPicker: UIViewController, UITableViewDelegate, UITableViewDataSource {
    //MARK: Variables
    var items: [String]?
    // 新增:保存选中回调,避免循环引用风险
    private var itemSelectedCallback: ((String) -> ())?
    
    //MARK: ViewController Events
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    //MARK: TableView Events
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items?.count ?? 0
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell")!
        cell.textLabel!.text = items![indexPath.row]
        return cell
    }
    
    // 新增:处理行选中事件,提升交互体验
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        if let selectedItem = items?[indexPath.row] {
            itemSelectedCallback?(selectedItem)
            self.dismiss(animated: true)
        }
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    //MARK: Support Methods
    func showListPicker(
        viewController: UIViewController,
        title: String? = "Select Item",
        message: String? = nil,
        items: [String]?,
        itemSelected: (@escaping (_ item: String) -> ())
    ) {
        // 修复2:将传入的items赋值给实例属性,确保数据源正确
        self.items = items
        self.itemSelectedCallback = itemSelected
        
        let alert = UIAlertController(
            title: title,
            message: message,
            preferredStyle: .alert
        )
        
        // 移除初始化frame,改用约束控制尺寸
        let tableView = UITableView(style: .plain)
        tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell")
        tableView.delegate = self
        tableView.dataSource = self
        tableView.rowHeight = 35
        tableView.backgroundColor = .white
        tableView.separatorInset.right = 15
        tableView.bounces = false
        tableView.layoutMargins = .init(top: 0, left: 0, bottom: 0, right: 0)
        tableView.layer.cornerRadius = 10
        
        // 修复1:禁用自动约束转换,确保自定义约束生效
        tableView.translatesAutoresizingMaskIntoConstraints = false
        
        alert.view.addSubview(tableView)
        
        // 更安全的方式获取alert内容容器,避免依赖subviews索引的不稳定问题
        guard let contentView = alert.view.subviews.first?.subviews.first else {
            return
        }
        
        // 批量激活约束,代码更简洁
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 80),
            tableView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -60),
            tableView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 10),
            tableView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -10),
            // 添加最小高度约束,确保数据较少时tableView也能正常显示
            tableView.heightAnchor.constraint(greaterThanOrEqualToConstant: 100)
        ])
        
        let okAction = UIAlertAction(title: "OK", style: .default) { [weak self] _ in
            if let row = tableView.indexPathForSelectedRow?.row, let selectedItem = self?.items?[row] {
                itemSelected(selectedItem)
            }
        }
        let cancelAction = UIAlertAction(title: "Cancel", style: .cancel)
        
        alert.addAction(okAction)
        alert.addAction(cancelAction)
        
        viewController.present(alert, animated: true)
    }
}

额外优化说明

  • 移除了message中的手动换行,改用约束控制tableView位置,避免不同设备上的显示异常
  • 替换了依赖alert.view.subviews[0]的不安全写法,改用更稳定的内容容器获取方式
  • 新增了行选中自动关闭弹窗的逻辑,提升用户交互体验
  • 添加了tableView最小高度约束,确保数据量少时也能正常展示

内容的提问来源于stack exchange,提问作者Joel S.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.28 20:22:39