textField: shouldChangeCharactersInRange: replaceString: в подклассе - PullRequest
6 голосов
/ 25 марта 2012

Я вложил в UITextField подкласс и хотел бы использовать метод, подобный textField:shouldChangeCharactersInRange:replacementString: внутри подкласса, чтобы получать уведомления при вводе символа и, если необходимо, блокировать изменение, но избегать установки делегирования полей для себя.

Я обнаружил, что если переопределить keyboardInput:shouldInsertText:isMarkedText: и keyboardInputShouldDelete:, я смогу получить желаемый эффект, к сожалению, эти методы являются закрытыми, и все, что использует класс, не сможет пройти через процесс отправки в App Store.

Кто-нибудь знает о публичном методе, который достигает того же самого и не требует, чтобы поле было его собственным делегатом?

UPDATE:

Я предложил создать отдельный объект только для того, чтобы быть делегатом, который сам может иметь делегата для пересылки сообщений.

Ответы [ 4 ]

2 голосов
/ 26 марта 2012

Одна из стратегий, которую мы рассмотрим здесь, - переопределить метод setDelegate: и затем выполнить некоторую пересылку сообщений. Вы можете использовать [super setDelegate: self], чтобы убедиться, что ваши звонки получают первые сообщения в сообщениях делегатов. В переопределении 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. @ Скотт Корскадден имеет и не рекомендует его.)

Самым распространенным шаблоном является создание 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 голосов
/ 25 марта 2012

Попытавшись создать подкласс UITextField прежде, я с тех пор научился избегать этого и вместо этого идти по пути делегата (у него есть аналогичный метод с именем - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string, который должен делать то, что, как я думаю, вы описали).

1 голос
/ 08 марта 2013

Для достижения этой цели вы можете поиграть с Objective-CСледующий код работает для меня.Идея такова:

  • в подклассе мы устанавливаем свойство delegate в self;
  • мы переопределяем setDelegate: метод, в котором мы храним предоставленный делегат в переменной (forwardDelegate);
  • путем переопределения respondsToSelector:, forwardInvocation: и methodSignatureForSelector: мы либо вызываем метод для self, либо пересылаем его в сохраненный 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
0 голосов
/ 25 марта 2012

Вы можете использовать метод делегата поля uitext,

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

}

И не забудьте установить textfield.delegate = self в ViewDidLoad.

...