UITextView作为自己的委托意味着无限循环

时间:2012-06-26 20:31:17

标签: iphone objective-c ios ipad delegates

我有一个UITextView的子类,我想把它作为自己的委托。这样我就可以覆盖textView:shouldChangeTextInRange:replacementText:方法,并防止输入连续的空格。

[SATextView awakeFromNib](SATextView是我的UITextView的子类)中,我做[self setDelegate:self];。当我按下textview开始编辑时,所有内容都冻结并最终停止,并且该回溯显示存在无限循环。

如果我实现所有委托方法,只有一个或没有,这没关系。如果这些方法是空的也没关系。

为什么会导致无限循环?只有使用UITextView(其他对象可以子类化并将委托设置为self,并且它不会出现此问题),似乎只会发生这种情况。我怎么能阻止它?或者有更好的方法让这个子类不能有连续的空格,

3 个答案:

答案 0 :(得分:1)

一个想法......你可以创建一个委托类,作为真正的委托和UITextView之间的中间人(因为你可能需要在一段时间后设置委托)。所以这个新类将实现委托协议,但是它也有自己的委托属性,这样你就可以转发textView:shouldChangeTextInRange:replacementText:,并且仍然可以在middleMan类中编辑空格。

答案 1 :(得分:0)

可以为对象订阅任意数量的观察者。所以可以订阅自己:

@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:@" "];
}

答案 2 :(得分: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

导致我回答这个问题的一个重要问题是我试图覆盖delegate以返回_externalDelegate,但这会产生一些奇怪的副作用(必须有内部代码取决于实际代表将被退回)。