2012-03-25 2 views
6

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

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

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

UPDATE:

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

+0

Можете ли вы уточнить? Не сразу понятно, почему вы не будете использовать textField: shouldChangeCharactersInRange :, то есть получите подкласс, чтобы установить его экземпляры в качестве своих собственных делегатов. – Obliquely

+1

Единственная проблема с настройкой его как собственного делегата - это пересылка событий фактическому делегату, который может захотеть ответить на события UITextField. В настоящее время я использую addTarget: action: forControlEvent: чтобы реагировать на эти события внутри себя. –

ответ

2

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

+0

Конечно, но это доступно только в том случае, если я устанавливаю текстовое поле как собственный делегат, чего я бы хотел избежать. –

+1

Я не люблю делать UITextField своим собственным делегатом - я обычно использую свой собственный подкласс ScottTextFieldValidator как класс делегата (который имеет все методы/состояние, в котором он нуждается). Нет никакой причины, по которой UITextField сам должен быть своим делегатом. –

+0

Да, я тоже склоняюсь к этому подходу. –

0

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

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

} 

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

2

Одна стратегия для изучения здесь - переопределить метод 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. @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... 
} 
+0

Есть ли способ, которым я могу переслать их без необходимости их реализации? Поэтому на него вызывается только методы, которые реализует мой подкласс, но все остальное передается следующему делегату? –

+1

Я так не думаю. Но для реализации пересылки для 7 сообщений в протоколе UITextFieldDelegate требуется всего пять минут. Учитывая, что это пользовательский интерфейс, и люди медленны по сравнению с отправкой сообщений, накладные расходы не имеют значения. – Obliquely

+1

Было бы неплохо вырезать код, хотя;) –

1

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

  • в подклассе мы устанавливаем delegate свойство к себе;
  • Мы переопределяем метод 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 
Смежные вопросы