textField:shouldChangeCharactersInRange:replacementString:in subclass

时间:2012-03-25 17:14:13

标签: iphone ios cocoa-touch delegates uitextfield

我已经将UITextField子类化了,我想在子类中使用类似于textField:shouldChangeCharactersInRange:replacementString:的方法,以便在输入字符时获得通知,并在必要时阻止更改,但是避免将字段委托给本身。

我发现如果我覆盖keyboardInput:shouldInsertText:isMarkedText:keyboardInputShouldDelete:我可以获得所需的效果,不幸的是这些方法是私有的,使用该类的任何内容都无法通过App Store提交过程。

任何人都知道一个公共方法可以达到同样的目的,并且不需要该字段是自己的委托吗?

更新

我接着建议创建一个单独的对象作为委托,它本身可以有一个委托来转发消息。

4 个答案:

答案 0 :(得分:2)

之前尝试过UITextField的子类,我已经学会了避免这种情况并转而使用委托路径(它有一个类似的方法叫做- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string,应该做我认为你所描述的)。

答案 1 :(得分:2)

这里要探索的一个策略是覆盖setDelegate:方法然后执行一些消息转发。您可以使用[super setDelegate: self]确保您的呼叫在委派消息中获得第一个dib。在你的setDelegate重写中:设置一个内部的ivar,例如

 - (void) setDelegate: (id<UITextFieldDelegate>) internalDelegate;
 {
     [setInternalDelegate: internalDelegate];
 }

然后,对于每个UITextField委托方法,在转发委托消息之前执行您的操作,例如

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
{
      // do your thing with range and replacement string

      // now forward message on the 'other' delegate    
       [[self internalDelegate] textField: self shouldChangeCharactersInRange: range replacementString: string];
}

通常情况下,您需要覆盖所有委托方法,即使大多数委托方法都是直接的。

更新您在评论中注意到转发方法引发了问题。如果是这样,那么传统的授权就是可行的方式。 (而且,一般情况下,它的方式 - 虽然我曾经使用过一次或两次转发代表,但我不确定,事后来看,它是绝对必要的而且我没有检查我是否使用UITextField完成了它。@ Scott Corscadden有并且不推荐它。)

最常见的模式是使ViewController能够查看UITextField是子视图的视图。如果您需要使用子类的特殊原因,您在答案中没有说。如果你正在将有趣的东西打包到UITextField中,那么它可能是,尽管你可能总是另一张海报建议并为UITextField创建一个伴侣类来完成这项工作并将其用作委托。在任何情况下,如果需要,您总是可以让委托对象在UITextField子类上调用额外的方法,例如

// in the delegate object class

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string;
{
      [delegate doSomeExtraThingInTheTextFieldSubclassThatItSeemsToMakeSenseToDoThereRatherThanHere];

      // maybe that's it, or maybe this object also wants to do something here...
}

答案 2 :(得分:1)

您可以使用Objective-C运行时来实现此目的。以下代码对我有用。 这个想法是:

  • 在子类中我们将delegate属性设置为self;
  • 我们覆盖setDelegate:方法,我们将提供的委托存储到变量(forwardDelegate);
  • 通过覆盖respondsToSelector:forwardInvocation:methodSignatureForSelector:,我们可以自行调用方法或将其转发给已保存的forwardDelegate

// MyTextField.h
@interface MyTextField : UITextField
@end

// MyTextField.m
@interface MyTextField () <UITextFieldDelegate>
@end

@implementation MyTextField {
    id forwardDelegate;
}

- (void) myTextFieldCommonInit
{
    [super setDelegate:self];
}

- (id) initWithCoder:(NSCoder *)coder
{
    if ((self = [super initWithCoder:coder])) {
        [self myTextFieldCommonInit];
    }
    return self;
}

- (id) initWithFrame:(CGRect)frame
{
    if ((self = [super initWithFrame:frame])) {
        [self myTextFieldCommonInit];
    }

    return self;
}

- (void) setDelegate:(id)delegate
{
    forwardDelegate = delegate;
}

- (BOOL) respondsToSelector:(SEL)selector
{
    if ([super respondsToSelector:selector]) {
        return YES;
    } else {
        return [forwardDelegate respondsToSelector:selector];
    }
}

- (void) forwardInvocation:(NSInvocation *)invocation
{
    if ([super respondsToSelector:[invocation selector]]) {
        [super forwardInvocation:invocation];
    } else if ([forwardDelegate respondsToSelector:[invocation selector]]) {
        [invocation invokeWithTarget:forwardDelegate];
    } else {
        [self doesNotRecognizeSelector:[invocation selector]];
    }
}

- (NSMethodSignature *) methodSignatureForSelector:(SEL)selector
{
    NSMethodSignature *signature = [super methodSignatureForSelector:selector];
    if (signature) {
        return signature;
    } else {
        return [forwardDelegate methodSignatureForSelector:selector];
    }
}

#pragma mark - UITextFieldDelegate

- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
    ...
}

@end

答案 3 :(得分:0)

您可以使用uitextfield的委托方法

- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string 
{

}

不要忘记在ViewDidLoad中设置textfield.delegate = self