扩展非自有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
相关产品推荐
相关产品推荐

