UITextView subclass as delegate of itself

2020-02-08 08:54发布

问题:

Let's say I add a UITextView to my UIView, and I want it to change its background color each time the contents change. I can do this by becoming the delegate of the UITextView and implementing textViewDidChange.

If I am using this behavior frequently though, it makes sense to create a UITextView subclass, which I will call ColorSwitchingTextView. It should include the color-switching behavior by default, so that any UIView can simply add it instead of a standard UITextView if it wants that behavior.

How do I detect changes in the content from within my ColorSwitchingTextView class? I don't think I can do something like self.delegate = self.

In summary, how can a UITextView subclass know when its contents change?

EDIT It seems I can use self.delegate = self, but this means that the UIViewController that uses the ColorSwitchingTextView can not also subscribe to the notifications. Once I use switchingTextView.delegate = self in the view controller, the subclass behavior no longer works. Any workarounds? I'm trying to get a custom UITextView that otherwise works like a regular UITextView.

回答1:

In your subclass, listen for the UITextViewTextDidChangeNotification notification and update the background color when you receive the notification, like this:

/* 
 * When you initialize your class (in `initWithFrame:` and `initWithCoder:`), 
 * listen for the notification:
 */
[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(myTextDidChange)
                                             name:UITextViewTextDidChangeNotification
                                           object:self];

...

// Implement the method which is called when our text changes:
- (void)myTextDidChange 
{
    // Change the background color
}

- (void)dealloc
{
    // Stop listening when deallocating your class:
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}


回答2:

Better to do it right way from the beginning.

What Apple and SOLID would suggest, is to subclass not the UITextView, but the UIView. In your custom UIColorTextView you will have member UITextView as subview and your UIColorTextView will be it's delegate. Further, your UIColorTextView will have it's own delegate and will pass required delegate callbacks from UITextView to it's delegate.

I had some task like this not with UITextView but with UIScrollView.



回答3:

In your subclass, add self as an observer to UITextViewTextDidChangeNotification.

That said, I disagree with the ongoing conversation that setting self as the delegate is a bad idea. For this particular case, sure, but only because there's a better way (UITextViewTextDidChangeNotification).



回答4:

You can use NSNotificationCenter.

Set the delegate to self in the subclass (never tried this, but you said it works), then in the view controller you want to get notifications, do

[[NSNotificationCenter defaultCenter] 
         addObserver:self 
         selector:@selector(textFieldDidBeginEditing:) 
         name:@"TextFieldDidNotification" object:nil];

and in the subclass:

NSDictionary *userInfo = [NSDictionary dictionaryWithObject:self forKey:@"textField"];
[[NSNotificationCenter defaultCenter] postNotificationName:@"TextFieldDidBeginEditingNotification" object:self userInfo:userInfo]

Now you can also pass any other info in the dictionary as well.