Adam
Adam

Reputation: 33146

textViewDidEndEditing: is not called

I'm programmatically replacing a UITextField with a UITextView, but this seems to break something in Apple's code.

The class that does the swap-over is the delegate for both. All the delegate methods on the FIELD work correctly - I use "didBeginEditing" to trigger the swap from FIELD -> VIEW.

The didBeginEditing / shouldBeginEditing methods on the VIEW are also invoked correctly.

However ... the shouldEndEditing / didEndEditing methods on the VIEW delegate are never invoked. It doesn't matter how I remove focus, they are never called (I have them breakpointed, with log statements too). e.g. NONE of the following work:

  1. Tap a different textfield on the screen (FIELD delegate gets "shouldBegin" and "didBegin" - VIEW delegate gets nothing)
  2. Use a gesture recognizer on a background view to invoke "resignFirstResponder" for each element on screen (if a different field is selected, then FIELD delegate gets "shouldEnd" and "didEnd". VIEW gets nothing even if it's selected)

The fact that should/did begin methods are called shows that the delegate has been assigned OK, and is functioning correctly - but why / how are the should/did end methods being ignored? It's as if Apple has a bug in their code for detecting the existence of those methods.

NB: I used Xcode autocomplete / content-assist to create the methods, so I'm confident there's no typos. Just to be clear:

-(BOOL)textViewShouldEndEditing:(UITextView *)textView
{
    textComments.text = textView.text;

    [textView.superview insertSubview:self.textComments aboveSubview:textView];
    [textView removeFromSuperview];

    return TRUE;
}

-(void)textViewDidEndEditing:(UITextView *)textView
{
    textComments.text = textView.text;

        [textView.superview insertSubview:self.textComments aboveSubview:textView];
        [textView removeFromSuperview];
}

-(BOOL)textViewShouldBeginEditing:(UITextView *)textView
{
    NSLog(@"blah" );

    return TRUE;
}

-(void)textViewDidBeginEditing:(UITextView *)textView
{
    NSLog(@"blah" );
}

Upvotes: 1

Views: 6700

Answers (3)

Adam
Adam

Reputation: 33146

I finally found the cause: some 3rd-party code was subscribing to Apple's keyboard-did-appear/disapper notifications, and removing itself as a listener.

Unfortunately, Apple's NSNotificationCenter cannot remove a single listener / callback selector - it has to remove all the callbacks of a given instance on a given notification pattern.

So, as a side-effect, this 3rd-party code was removing my callback selector, even though none of my own code removed it. I was setting / resetting delegates in the keyboard notifications. The exact timings that Apple fires-off keyboard appear/disappear methods seems to be slightly different (consistently) for textfields and textviews, and that was why the behaviour only affected one type not the other.

My guess is that Dominic might be seeing a similar problem - and that his call to re-set the delegate "nudges" the timing of some notifications (accidentally), thereby fixing it.

Upvotes: 3

Dominic Sander
Dominic Sander

Reputation: 2704

I had today the same problem. It occured only on my iPad, not in the simulator. It occured on the iPad not always, but most. I fixed it by "refirming" the delegate ... sounds like nonsens, because it is assigned within the delegate-method itself, but it works for me.

-(void)textViewDidBeginEditing:(UITextField *)textField  {
NSLog(@"textfield began");
textField.delegate = self;
}

Upvotes: 2

aryaxt
aryaxt

Reputation: 77646

I beleive you need to return true in the following method: textViewShouldEndEditing. You should be getting a warning if you are not returning, because this method suppose to return a BOOL

-(BOOL)textViewShouldEndEditing:(UITextView *)textView
{
    textComments.text = textView.text;

    [textView.superview insertSubview:self.textComments aboveSubview:textView];
    [textView removeFromSuperview];

    return YES;
}

Upvotes: 0

Related Questions