如何在继承类的扩展中重写函数?解决UIScrollView与UITableView冲突
解决UIScrollView与UITableView扩展方法冲突的问题
这个问题我之前也碰到过,确实挺坑的——Swift里扩展无法重写父类的方法,而UITableView本身就是UIScrollView的子类,所以你在两个扩展里定义同名的scrollToBottom方法,就触发了「Declarations in extensions cannot override yet」的报错。下面给你几个实用的解决思路,按需选择就行:
方案一:给UITableView使用不同的方法名
最简单直接的方式就是避免重名,给UITableView的滚动方法起个专属名字,比如scrollToLastCell:
// UIScrollView的通用滚动到底部实现 extension UIScrollView { func scrollToBottom(animated: Bool) { let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.height + contentInset.bottom) setContentOffset(bottomOffset, animated: animated) } } // UITableView专属的滚动到最后一个cell的实现 extension UITableView { func scrollToLastCell(animated: Bool) { guard numberOfSections > 0 else { return } let lastSection = numberOfSections - 1 guard numberOfRows(inSection: lastSection) > 0 else { return } let lastRow = numberOfRows(inSection: lastSection) - 1 let indexPath = IndexPath(row: lastRow, section: lastSection) scrollToRow(at: indexPath, at: .bottom, animated: animated) } }
优点:逻辑清晰,完全避免冲突;缺点:调用时需要区分类型使用不同方法。
方案二:用协议扩展实现差异化逻辑
通过定义协议并提供默认实现,让UIScrollView和UITableView分别遵守协议,UITableView可以自定义实现覆盖默认逻辑:
// 定义协议 protocol ScrollableToBottom { func scrollToBottom(animated: Bool) } // 给UIScrollView类型提供默认实现 extension ScrollableToBottom where Self: UIScrollView { func scrollToBottom(animated: Bool) { let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.height + contentInset.bottom) setContentOffset(bottomOffset, animated: animated) } } // 让UIScrollView遵守协议,使用默认实现 extension UIScrollView: ScrollableToBottom {} // 让UITableView遵守协议,自定义实现 extension UITableView: ScrollableToBottom { func scrollToBottom(animated: Bool) { guard numberOfSections > 0 else { return } let lastSection = numberOfSections - 1 guard numberOfRows(inSection: lastSection) > 0 else { return } let lastRow = numberOfRows(inSection: lastSection) - 1 let indexPath = IndexPath(row: lastRow, section: lastSection) scrollToRow(at: indexPath, at: .bottom, animated: animated) } }
优点:调用时统一使用scrollToBottom方法,无需区分类型;缺点:需要额外定义协议,稍显繁琐。
方案三:在UIScrollView扩展中判断类型分支处理
如果不想额外定义协议或方法名,可以在UIScrollView的扩展里判断当前实例是否是UITableView,然后执行不同逻辑:
extension UIScrollView { func scrollToBottom(animated: Bool) { if let tableView = self as? UITableView { // UITableView专属逻辑:滚动到最后一个cell guard tableView.numberOfSections > 0 else { return } let lastSection = tableView.numberOfSections - 1 guard tableView.numberOfRows(inSection: lastSection) > 0 else { return } let lastRow = tableView.numberOfRows(inSection: lastSection) - 1 let indexPath = IndexPath(row: lastRow, section: lastSection) tableView.scrollToRow(at: indexPath, at: .bottom, animated: animated) } else { // 通用UIScrollView逻辑:滚动到内容底部 let bottomOffset = CGPoint(x: 0, y: contentSize.height - bounds.height + contentInset.bottom) setContentOffset(bottomOffset, animated: animated) } } }
优点:只需要一个扩展,调用简单;缺点:把UITableView的逻辑耦合在UIScrollView的扩展里,不符合单一职责原则,后期维护可能麻烦。
内容的提问来源于stack exchange,提问作者TruMan1
相关产品推荐
相关产品推荐

