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

Xcode升级后UITableView单元格按钮点击无响应问题排查

Xcode 11升级后UITableView点击无响应问题排查

嘿,针对你升级Xcode11后遇到的UITableView单元格点击/按钮无响应、仅部分区域变灰的问题,我帮你梳理几个最可能的原因和解决方案:

1. 重复给按钮绑定Target导致响应异常

你当前在cellForRowAt方法里,每次复用单元格时都会调用addTarget给按钮绑定事件。这种写法在Xcode旧版本可能没问题,但Xcode11之后UIKit的事件响应机制对重复绑定的处理更严格,会导致同一个按钮被绑定多份相同的target-action,最终引发点击事件无法正确触发,甚至完全无响应。

修复方案:
把按钮的事件绑定逻辑移到自定义单元格PostTableViewCell的初始化方法里,用代理/闭包把事件传递给ViewController,避免重复绑定:

首先在PostTableViewCell中添加代理协议:

import UIKit

protocol PostCellDelegate: AnyObject {
    func didTapCommentButton(for post: Post)
    func didTapFavoriteButton(for post: Post)
}

class PostTableViewCell: UITableViewCell {
    weak var delegate: PostCellDelegate?
    private var currentPost: Post?
    
    @IBOutlet weak var btnComment: UIButton!
    @IBOutlet weak var favoritebutton: UIButton!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // 只在初始化时绑定一次事件
        btnComment.addTarget(self, action: #selector(commentTapped), for: .touchUpInside)
        favoritebutton.addTarget(self, action: #selector(favoriteTapped), for: .touchUpInside)
    }
    
    func set(post: Post) {
        currentPost = post
        // 这里写你的UI配置逻辑,比如设置标题、内容等
    }
    
    @objc private func commentTapped() {
        guard let post = currentPost else { return }
        delegate?.didTapCommentButton(for: post)
    }
    
    @objc private func favoriteTapped() {
        guard let post = currentPost else { return }
        delegate?.didTapFavoriteButton(for: post)
    }
}

然后在HomeViewController中实现代理,并修改cellForRowAt:

extension HomeViewController: PostCellDelegate {
    func didTapCommentButton(for post: Post) {
        postKey = post._documentId
        performSegue(withIdentifier: "toCommentsList", sender: self)
    }
    
    func didTapFavoriteButton(for post: Post) {
        postKey = post._documentId
        // 这里写你原来的favupdate逻辑
        let userMarkRef = Firestore.firestore().collection("users").document(Auth.auth().currentUser!.uid).collection("marked_posts").document(postKey)
        let postRef = Firestore.firestore().collection("posts").document(postKey)
        postRef.getDocument{(document, error) in
            // 你的原有逻辑...
        }
    }
}

// 修改cellForRowAt中的postCell部分
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.row == 0 && scores1.count == 1 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "SmileMiles") as! ScoresCellInHomeScreen
        cell.set(scores: scores1[indexPath.row])
        return cell
    } else if posts.count > (indexPath.row - 1 ) {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
        // 只设置代理,不再重复addTarget
        cell.delegate = self
        cell.set(post: posts[indexPath.row - 1 ])
        return cell
    } else {
        let cell = UITableViewCell()
        cell.isUserInteractionEnabled = false
        return cell
    }
}

2. 空单元格逻辑引发的布局/响应冲突

你在cellForRowAt的else分支返回了一个空的UITableViewCell(),虽然理论上numberOfRowsInSection返回的是scores1.count + posts.count,但异步加载数据时如果reload时机不对,可能出现行号超出范围的情况,这个空单元格会干扰tableView的事件响应链,导致部分区域变灰但无响应。

修复方案:
先严格控制行数,确保numberOfRowsInSection的返回值和单元格逻辑完全匹配:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // 只有scores1有数据时才显示顶部固定单元格
    let fixedRowCount = scores1.isEmpty ? 0 : 1
    return fixedRowCount + posts.count
}

然后优化cellForRowAt的逻辑,避免出现超出范围的情况:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if !scores1.isEmpty && indexPath.row == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "SmileMiles") as! ScoresCellInHomeScreen
        cell.set(scores: scores1[0])
        return cell
    } else {
        // 计算正确的post索引
        let postIndex = scores1.isEmpty ? indexPath.row : indexPath.row - 1
        guard postIndex < posts.count else {
            // 兜底返回不可交互的占位单元格
            let cell = UITableViewCell()
            cell.isUserInteractionEnabled = false
            return cell
        }
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! PostTableViewCell
        cell.delegate = self
        cell.set(post: posts[postIndex])
        return cell
    }
}

3. 自动高度设置冲突导致点击区域异常

你在viewWillAppear中设置了tableView.rowHeight = UITableView.automaticDimension,同时又在heightForRowAt中给第一行设置固定高度,其他行返回自动高度。Xcode11之后UITableView的自动高度计算逻辑有调整,这种混合设置可能导致单元格的可点击区域计算错误,出现“一半变灰”的情况。

修复方案:
统一高度配置,保留heightForRowAt的逻辑,去掉viewWillAppear中的rowHeight设置:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    tableView.estimatedRowHeight = 200
    // 移除这行代码:tableView.rowHeight = UITableView.automaticDimension
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    if !scores1.isEmpty && indexPath.row == 0 {
        return 150
    } else {
        return UITableView.automaticDimension
    }
}

同时确保自定义单元格PostTableViewCell的约束是完整的:从contentView的顶部到底部都有连续的约束,这样自动高度才能正确计算,点击区域也会覆盖整个单元格。

4. 清理无用代码避免潜在干扰

你在viewDidLoad中创建了一个完全无用的AViewController和MyTabBarItem,这段代码不仅没有作用,还可能不小心干扰视图层级或事件响应,建议直接删除:

// 删掉以下无用代码
var AViewController: UIViewController = UIViewController()
var MyTabBarItem: UITabBarItem = UITabBarItem(title: nil, image: UIImage(named: "pencil")?.withRenderingMode(UIImage.RenderingMode.alwaysOriginal), selectedImage: UIImage(named: "pencil"))
AViewController.tabBarItem = MyTabBarItem

内容的提问来源于stack exchange,提问作者user12008081

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:57:14