UITextView as a native delegate means an infinite loop

I have a subclass of UITextView and I would like to make it my own delegate. So that I can override the method textView:shouldChangeTextInRange:replacementText:and prevent the input of consecutive spaces.

In [SATextView awakeFromNib](SATextView is my subclass of UITextView), I do [self setDelegate:self];. When I click on the text to start editing, everything freezes and finally stops, and this return line shows that there was an infinite loop.

It doesn’t matter if I implement all the methods of the delegate, only one or none. It doesn't matter if these methods are empty.

Why does this cause an endless loop? This only happens if with a UITextView (you can subclass and set the delegate to other objects and it will not have this problem). And how can I stop him? Or is there a better way to prevent this subclass from having consecutive spaces,

+5
source share
3 answers

... , UITextView ( , , ). , , , textView: shouldChangeTextInRange: replacementText:, middleMan.

+1

. , :

@implementation MyTextView 

-(id) initWithFrame:(CGRect)frame // or initWithCoder: for loading from nib
{
    self = [super initWithFrame:frame];
    if(self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textViewTextDidChangeNotification:) name:UITextViewTextDidChangeNotification object:self];
    }
    return self;
}

-(void)textViewTextDidChangeNotification:(NSNotification*)n
{
    self.text = [self.text stringByReplacingOccurrencesOfString:@"  " withString:@" "];
}
0

, . , , textView:shouldChangeTextInRange:replacementText:, .

#import "INFTextView.h"

@interface INFTextView () <UITextViewDelegate>

@property (nonatomic, weak) id<UITextViewDelegate> externalDelegate;

@end

@implementation INFTextView

- (id)init {
    self = [super init];
    if (!self) {
        return nil;
    }

    self.delegate = self;

    return self;
}

- (void)awakeFromNib {
    self.delegate = self;
}

- (void)setDelegate:(id<UITextViewDelegate>)delegate {
    // we always want self to be the delegate, if someone is interested in delegate calls we will forward those on if applicable
    if (delegate == self) {
        [super setDelegate:self];
        return;
    } else {
        // capture that someone else is interested in delegate calls
        _externalDelegate = delegate;
    }
}

- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
    NSCharacterSet *unsupportedCharacterSet = [[NSCharacterSet characterSetWithCharactersInString:kINFSupportedCharacters] invertedSet];

    NSRange unsupportedCharacterRange = [text rangeOfCharacterFromSet:unsupportedCharacterSet];
    if (unsupportedCharacterRange.location == NSNotFound) {
        return YES;
    } else {
        return NO;
    }
}

- (BOOL)textViewShouldBeginEditing:(UITextView *)textView {
    if ([_externalDelegate respondsToSelector:@selector(textViewShouldBeginEditing:)]) {
        return [_externalDelegate textViewShouldBeginEditing:textView];
    }

    return YES;
}

- (BOOL)textViewShouldEndEditing:(UITextView *)textView {
    if ([_externalDelegate respondsToSelector:@selector(textViewShouldEndEditing:)]) {
        return [_externalDelegate textViewShouldEndEditing:textView];
    }

    return YES;
}

- (void)textViewDidBeginEditing:(UITextView *)textView {
    if ([_externalDelegate respondsToSelector:@selector(textViewDidBeginEditing:)]) {
        [_externalDelegate textViewDidBeginEditing:textView];
    }
}

- (void)textViewDidEndEditing:(UITextView *)textView {
    if ([_externalDelegate respondsToSelector:@selector(textViewDidEndEditing:)]) {
        [_externalDelegate textViewDidEndEditing:textView];
    }
}

- (void)textViewDidChange:(UITextView *)textView {
    if ([_externalDelegate respondsToSelector:@selector(textViewDidChange:)]) {
        [_externalDelegate textViewDidChange:textView];
    }
}

- (void)textViewDidChangeSelection:(UITextView *)textView {
    if ([_externalDelegate respondsToSelector:@selector(textViewDidChangeSelection:)]) {
        [_externalDelegate textViewDidChangeSelection:textView];
    }
}

@end

One big flip-flop that led me to this question was that I was trying to override delegateto return _externalDelegate, but it caused some strange side effects (there should be an internal code that depends on the actual delegate being returned).

0
source

All Articles