Marius
Marius

Reputation: 4016

UITextField with "multiple" delegates

I'm trying to create a text field that would be able to respond to the following:

-(BOOL)textFieldShouldEndEditing:(UITextField *)textField

To do so i have a UITextField subclass which is a delegate for itself:

[self setDelegate:self]

QUESTION: What would be the easiest way to implement delegate methods in a subclass, but still allowing an outside object to be a delegate as well and recieve the same messages?

Thanks

Upvotes: 6

Views: 4739

Answers (3)

Paulo Mattos
Paulo Mattos

Reputation: 19339

I was having the exact same issue (in Swift 3). I solved the problem overriding the delegate property from the UITextField class.

During my custom view initialization, I hook up my own internal delegate:

class CustomTextField: UITextField, UITextFieldDelegate {

    override public init(frame: CGRect) {
        super.init(frame: frame)
        initCustomTextField()
    }

    required public init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initCustomTextField()
    }

    private func initCustomTextField() {
        super.delegate = self // Note the super qualifier.
    }

    ...

Now we need to override the aforementioned delegate property:

private weak var userDelegate: UITextFieldDelegate?

override var delegate: UITextFieldDelegate? {
    get { return userDelegate }
    set { userDelegate = newValue }
}

Finally, on each UITextFieldDelegate protocol method you must forward the call to the external delegate, if any:

func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
    // Do your thing here, and then forward:
    return self.delegate?.textFieldShouldBeginEditing?(self) ?? true
}

func textFieldDidBeginEditing(_ textField: UITextField) {
    // Do your thing here, and then forward:
    self.delegate?.textFieldDidBeginEditing?(self)
}

...

One caveat if you plan to support iOS 10 as well:

func textFieldDidEndEditing(_ textField: UITextField) {
    self.delegate?.textFieldDidEndEditing?(self)
}

/// This method will be called, instead of the above, on iOS ≥ 10.
@available(iOS 10.0, *)
func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) {
    self.delegate?.textFieldDidEndEditing?(self, reason: reason)
}

Upvotes: 15

Retro
Retro

Reputation: 4005

For creating you own delegate you need to define new protocol into your subclass

@protocol MyUItestFieldDelegate <NSObject>

- (void)customUITextFieldDelegateMethod;

@end

which you can use into your controller like

@interface MyViewController : UIViewController <MyUItestFieldDelegate>

Upvotes: 0

Mert Buran
Mert Buran

Reputation: 3017

You can make use of Notifications. Make it that text field post notification, like the following:

[[NSNotificationCenter defaultCenter] postNotificationName:@"custom notification name" object:self];

and add observer to the class which is supposed to be external delegate:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(cacheUpdated:) name:@"custom notification name" object:nil];

That way, text field post notification which means it took a certain action and your external delegate class will be notified since it's already been listening to that kind of notifications. Hope it helps.

Upvotes: 0

Related Questions