Search code examples
iosswiftuitextview

How can a custom UITextView support 2 delegates - Both internal delegate and external delegate?


I have a custom UITextView, which itself contain an internal private delegate.

import UIKit

class CustomTextView: UITextView {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
        
        self.delegate = self
    }
}

extension CustomTextView: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        print("CustomTextView delegate textViewDidChange (Performing operation like setNeedsDisplay to implement custom drawing)")
    }
}

However, if I start to apply this CustomTextView, and applying an external delegate, it will broken because its initial internal delegate will not be executed.

import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var customTextView: CustomTextView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        customTextView.delegate = self
    }
}

extension ViewController: UITextViewDelegate {
    func textViewDidChange(_ textView: UITextView) {
        print("ViewController delegate textViewDidChange")
    }
}

If we execute the above code, only

ViewController delegate textViewDidChange

will be printed.

I was wondering, what are some good design, to ensure multiple delegates are supported, so that both will be printed?

CustomTextView delegate textViewDidChange (Performing operation like setNeedsDisplay to implement custom drawing)
ViewController delegate textViewDidChange

Thanks.


Solution

  • You can add a custom other delegate property and forward calls to it with the internal delegate

    class CustomTextView: UITextView {
        weak var other:UITextViewDelegate?
        required init(coder aDecoder: NSCoder) {
            super.init(coder: aDecoder)! 
            self.delegate = self
        }
    }
    
    extension CustomTextView: UITextViewDelegate {
        func textViewDidChange(_ textView: UITextView) {
            print("CustomTextView delegate textViewDidChange (Performing operation like setNeedsDisplay to implement custom drawing)")
            other?.textViewDidChange?(textView)
        }
    }
    

    Then

    override func viewDidLoad() {
        super.viewDidLoad()
        
        customTextView.other = self
    }