Is there a delegate call for when the text is changed on a UITextView?
Asked Answered
C

7

14

When I set my UITextView programmatically like this:

[self.textView setText:@""];

The delegate method textViewDidChange: does not get called. Is there a way I can find that without making a UITextView subclass?

Crewel answered 27/8, 2014 at 22:51 Comment(2)
the solution: https://mcmap.net/q/63908/-uitextfield-text-change-eventBinal
insertText(), however, does invoke textViewDidChange.Irishirishism
N
31

When manually setting the text of a UITextView with code, the textViewDidChange: method does not get called. (If you have your text view's delegate set, it will get called when the user edits it, though.)

One possible workaround would be to manually call textViewDidChange: anytime you edit the text. For example:

[self.textView setText:@""];
[self textViewDidChange:self.textView];

Kind of a hackish way of doing it, but it gets the job done.

Nanna answered 27/8, 2014 at 23:3 Comment(3)
It's an interesting approach. Mostly, people don't consider calling delegate methods of frameworks manually. However, it's a nice idea.Cabalist
Definitely not hackish, IMO. Methods are meant to be called and this one is staring you right in the face.Irishirishism
I think that it's safer to use [self.textView.delegate textViewDidChange:self.textView], in case the delegate changes to a different object than self.Venita
C
9

I upvoted @rebello95's response because it is one approach. But another, less hacky approach is to do as

- (void)whereIManuallyChangeTextView
{//you don't actually have to create this method. It's simply wherever you are setting the textview to empty
  [self.textView setText:@""];
  [self respondToChangeInTextView:self.textView];
}
    
- (void)textViewDidChange:(UITextView *)textView
{
  //...some work and then
  [self respondToChangeInTextView:textView];
}
    
- (void)respondToChangeInTextView:(UITextView *)textView
{
  //what you want to happen when you programmatically/manually or interactively change the textview
}

This snippet exemplifies a respectable pattern that will make your code more readable.

Contraband answered 27/8, 2014 at 23:19 Comment(0)
L
4

In swift you could override the text variable from the UITextView class:

class MyTextView: UITextView {

    override public var text: String? {
        didSet {
            self.textViewDidChange(self)
        }
    }

}
Lepage answered 21/9, 2018 at 11:9 Comment(2)
this wont work cause it doesnt get called when the user is typingDaddy
It should only enhance the textview to call the delegate whenever text is changed through code @LucasChweLindeman
B
2

Old post, but I had the same problem and thought I would share my solution (in Swift).

textViewDidChange(_ textView: UITextView) does not get called by just setting the text property, but it does get called when using replace(range: UITextRange, withText: String). So you need to create a UITextRange for the entire string of the UITextView and replace it with a new string.

// Create a range of entire string
let textRange = textView.textRange(from: textView.beginningOfDocument, to: textView.endOfDocument)
// Create a new string
let newText = ""
// Call Replace the string in your textView with the new string
textView.replace(textRange!, withText: newText)

That should do it. Of course, you need to set up UITextViewDelegate for this to work:

class ViewController: UIViewController, UITextViewDelegate {
Baluchistan answered 9/7, 2018 at 10:54 Comment(1)
tried this, but using textView.replace does not call the delegate for meIrizarry
T
0

You could also subclass UITextView and override setText to include

[self textViewDidChange:self.textView]

so that you don't have to call it every time you set the text of your UITextView.

Terhune answered 20/4, 2020 at 19:12 Comment(0)
F
0

delegate method textDidChange does not respond to programmatical changes in textes, you can use observation to get notified

  1. declare your text view variable with @objc dynamic
  2. declare and hold a variable with type NSKeyValueObservation
  3. use function observe(_:changeHandler:) bind your text view's text property, hold the return value with variable declared in step 2
  4. observe changes in changeHandler

example:

@objc dynamic private var textView: UITextView!
private var observation: NSKeyValueObservation?

func bind() {
    observation = observe(\.textView.text, options: [.old, .new]) { object, change in
        print(object, change)
    }
}
Festoonery answered 4/11, 2021 at 2:35 Comment(0)
F
-1

use this instead: (this won't reset the current text)

[self.textView insertText:@"something"];

this will call the delegate and will add text where the cursor is. Of course if you want to reset the whole text you can either:

[self.textView setText:@""];
[self textViewDidChange:self.textView];

or

[self.textView setText:@""];
[self.textView insertText:@"something"];
Frontogenesis answered 29/4, 2016 at 14:33 Comment(1)
insertText doesn't call the delegate. Also: "textViewDidChange: Discussion The text view calls this method in response to user-initiated changes to the text. This method is not called in response to programmatically initiated changes." via: developer.apple.com/reference/uikit/uitextviewdelegate#jumpTo_7Externalism

© 2022 - 2024 — McMap. All rights reserved.