Good question. Here is a not so good answer, since it requires you to rewrite all the delegate-methods and is therefore not stable across iOS-versions in case the delegate methods change over time.
In this approach the ViewController and the CustomTextField both have access to delegate-events.
class CustomTextView: UITextView {
override var delegate: UITextViewDelegate? {
set {
superDelegate = newValue
} get {
return superDelegate
}
}
private weak var superDelegate: UITextViewDelegate?
init() {
super.init(frame: .zero, textContainer: nil)
super.delegate = self
}
func textDidChange(text: String?) {
// do something
}
}
extension BoundTextView: UITextViewDelegate {
public func textViewDidChange(_ textView: UITextView) {
// catch text-change events here
textDidChange(text: String?)
superDelegate?.textViewDidChange?(textView)
}
public func textViewDidEndEditing(_ textView: UITextView) {
superDelegate?.textViewDidEndEditing?(textView)
}
public func textViewDidChangeSelection(_ textView: UITextView) {
superDelegate?.textViewDidChange?(textView)
}
public func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
return superDelegate?.textViewShouldBeginEditing?(textView) ?? false
}
public func textViewDidBeginEditing(_ textView: UITextView) {
superDelegate?.textViewDidBeginEditing?(textView)
}
public func textViewShouldEndEditing(_ textView: UITextView) -> Bool {
return superDelegate?.textViewShouldEndEditing?(textView) ?? false
}
public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
return superDelegate?.textView?(textView, shouldChangeTextIn: range, replacementText: text) ?? false
}
public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return superDelegate?.textView?(textView, shouldInteractWith: URL, in: characterRange, interaction: interaction) ?? false
}
public func textView(_ textView: UITextView, shouldInteractWith textAttachment: NSTextAttachment, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool {
return superDelegate?.textView?(textView, shouldInteractWith: textAttachment, in: characterRange, interaction: interaction) ?? false
}
}
We override the delegate and store a reference to it in a separate variable (called superDelegate). The CustomTextField assigns itself to super.delegate and implements the UITextView-delegate. We have to make sure that every delegate-event triggers the corresponding superDelegate's event.
Our 'ViewController' can now assign itself as the CustomTextView's delegate:
class ViewController: UIViewController {
...
lazy var textField: CustomTextView {
let textView = CustomTextField()
textView.delegate = self
return textField
}()
...
}
extension ViewController: UITextViewDelegate {
// implement only the delegate-methods you need
}
Now both, the ViewController and the CustomTextField, have both access to the UITextFieldDelegate.