自定义UITextView如何同时支持内部与外部两个delegate?
解决方案
方案1:重写delegate属性做中间转发(最常用,无侵入)
这个方案兼容UITextView原有使用习惯,外部开发者无感知,无需修改原有调用逻辑。
核心思路是:自定义控件内部始终持有自己作为真实delegate,单独存储外部设置的delegate,收到系统回调时先执行内部逻辑,再转发给外部delegate。
实现代码
import UIKit class CustomTextView: UITextView { // 存储外部传入的delegate private weak var externalDelegate: UITextViewDelegate? required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder)! // 内部始终把自己设为真实的系统delegate super.delegate = self } // 重写delegate的get/set override weak var delegate: UITextViewDelegate? { get { return externalDelegate } set { externalDelegate = newValue } } } extension CustomTextView: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { // 第一步:执行内部私有逻辑 print("CustomTextView delegate textViewDidChange (Performing operation like setNeedsDisplay to implement custom drawing)") // 第二步:转发回调给外部delegate(如果外部实现了该方法) externalDelegate?.textViewDidChange?(textView) } // 其他需要用到的UITextViewDelegate方法都按同样逻辑转发即可,例如: func textViewDidBeginEditing(_ textView: UITextView) { // 内部逻辑(如果有) externalDelegate?.textViewDidBeginEditing?(textView) } func textViewDidEndEditing(_ textView: UITextView) { // 内部逻辑(如果有) externalDelegate?.textViewDidEndEditing?(textView) } // 其余代理方法按需添加转发即可 }
效果
外部ViewController无需修改任何代码,运行后会依次输出两行日志,符合预期。
方案2:多代理队列(适合需要支持多个外部代理的场景)
如果需要同时支持多个外部对象监听回调,可以用弱引用容器存储所有代理对象,收到系统回调时遍历调用。
实现代码
import UIKit class CustomTextView: UITextView { // 用NSHashTable存储代理,weak持有避免循环引用 private let delegates = NSHashTable<UITextViewDelegate>.weakObjects() required init(coder aDecoder: NSCoder) { super.init(coder: aDecoder)! super.delegate = self // 把自己也加入代理队列,优先执行内部逻辑 addDelegate(self) } // 暴露给外部添加代理的方法 func addDelegate(_ delegate: UITextViewDelegate) { delegates.add(delegate) } // 也可以提供移除代理的方法 func removeDelegate(_ delegate: UITextViewDelegate) { delegates.remove(delegate) } } extension CustomTextView: UITextViewDelegate { func textViewDidChange(_ textView: UITextView) { // 遍历所有代理执行回调 delegates.allObjects.forEach { $0.textViewDidChange?(textView) } } // 其他代理方法同样遍历调用即可 }
外部使用示例
override func viewDidLoad() { super.viewDidLoad() customTextView.addDelegate(self) }
这种方案的优势是可以支持任意数量的监听者,劣势是需要修改外部原有调用逻辑,不再兼容原生delegate赋值的写法。
内容的提问来源于stack exchange,提问作者Cheok Yan Cheng
相关产品推荐
相关产品推荐

