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

扩展非自有ViewController的tableView willDisplay方法未调用,如何修改Cell样式?

解决扩展中UITableViewDelegate方法未被调用的问题

这个问题我之前也踩过坑,主要是因为UITableView的Delegate方法基于Objective-C runtime机制,而Swift扩展的方法在某些场景下无法被runtime识别,或者被原类的方法覆盖了。下面给你几个可行的解决方案:

1. 给扩展方法添加@objc标记

UITableView的Delegate是Objective-C协议,Swift扩展中实现的这类方法如果没有显式标记@objc,Objective-C runtime可能找不到这个方法,导致不会被调用。修改你的扩展代码:

extension NotMyViewController {
    @objc public func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.textLabel?.font = UIFont(name: "DesignersChoice", size: 12)
    }
}

⚠️ 注意:如果NotMyViewController本身已经实现了tableView(_:willDisplay:forRowAt:)方法,那么类自身的实现会优先执行,扩展里的代码还是不会被调用,这时你需要用下面的方法。

2. 使用Method Swizzling替换原方法实现

如果原类已经实现了该方法,或者上面的方案无效,Method Swizzling(方法交换)是个可靠的办法,它能让我们的代码逻辑插入到原方法执行前后,同时保留原方法的功能(如果需要的话)。

示例代码:

import ObjectiveC

extension NotMyViewController {
    static let swizzleWillDisplayCell: Void = {
        let originalSelector = #selector(tableView(_:willDisplay:forRowAt:))
        let swizzledSelector = #selector(swizzled_tableView(_:willDisplay:forRowAt:))
        
        guard let originalMethod = class_getInstanceMethod(self, originalSelector),
              let swizzledMethod = class_getInstanceMethod(self, swizzledSelector) else {
            return
        }
        
        // 先尝试添加原方法的空实现(如果原类没实现的话)
        let didAddMethod = class_addMethod(self, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod))
        
        if didAddMethod {
            class_replaceMethod(self, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod))
        } else {
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }()
    
    @objc private func swizzled_tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        // 先执行我们的自定义样式设置
        cell.textLabel?.font = UIFont(name: "DesignersChoice", size: 12)
        
        // 调用原方法的逻辑(方法交换后,这里调用swizzled方法实际是执行原方法)
        swizzled_tableView(tableView, willDisplay: cell, forRowAt: indexPath)
    }
    
    // 确保只在类首次加载时执行一次方法交换
    override class func initialize() {
        guard self === NotMyViewController.self else { return }
        _ = swizzleWillDisplayCell
    }
}

⚠️ 注意:Method Swizzling要谨慎使用,一定要确保只执行一次(上面的代码通过initialize加判断避免了子类触发重复交换),否则可能导致逻辑混乱。

3. 备选方案:全局或自定义Cell设置

如果上面的方法都不符合你的需求,还有两个思路:

  • 全局Appearance设置:如果这个字体样式可以应用到所有UITableViewCell,直接在App启动时设置:
    UITableViewCell.appearance().textLabel?.font = UIFont(name: "DesignersChoice", size: 12)
    
  • 自定义Cell替换:创建一个继承自UITableViewCell的子类,在子类中设置textLabel字体,然后通过runtime替换原VC中使用的Cell类(这个操作相对复杂,适合需要大量自定义样式的场景)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:20:14