2012-01-13 4 views
4

Это довольно сложная иерархия наследования, так что нести меня (я попытался упростить ситуацию, а не указать точный случай, который я использую, что еще сложнее): -Objective-C - Подкласс делегата в подклассе

Предположим, я создаю подкласс UITextField под названием TextField, который является моим собственным пользовательским расширенным текстовым полем общего назначения. Теперь, чтобы обеспечить эту расширенную функциональность, в методе от TextField, я установил super.delegate = self, чтобы все методы делегата от UITextField отправлены в TextField. TextField реализует протокол UITextFieldDelegate и получает эти методы делегатов, чтобы сделать что-то интересное.

Однако, в свою очередь, я хочу сделать так, чтобы TextField имеет делегат. Поэтому я создаю новый протокол под названием TextFieldDelegate (обратите внимание на отсутствие UI -prefix!) И дайте TextField ivar id<TextFieldDelegate> __weak delegate с соответствующим свойством, чтобы другие классы могли получать методы делегатов от TextField.

Надеюсь, вы все еще со мной, потому что до сих пор я не делал ничего слишком сложного. Но скажем, что теперь я создаю еще один пользовательский подкласс TextField, назовем его PasswordTextField (в реальной жизни, вероятно, не нужно будет создавать подкласс только для реализации функций пароля, но предположим, что существует довольно сложная реализация что потребует этого).

Предположим также, что я хочу сделать так, чтобы PasswordTextField (который, как и TextField имеет свойство делегата), может отправлять расширенный набор методов делегатов. Например, возможно, он может отправить метод passwordIsSecure, который отправляется после того, как пароль достигнет требуемого уровня сложности. Теперь, поскольку это поведение не было найдено в регулярном TextField, я создаю новый протокол: PasswordTextFieldDelegate <TextFieldDelegate>, который определяет новые методы делегирования для PasswordTextFieldи наследует все методы делегатов, отправленные TextField.

Проблема в следующем: как это реализовать в PasswordTextField? Вещи, которые не работают:

Наследование

Я не могу просто наследовать делегата от TextField, потому что делегат TextField «s соответствует только к TextFieldDelegate и не PasswordTextFieldDelegate, поэтому я не могу отправить методы, как [delegate passwordIsSecure], потому что TextFieldDelegate не имеет такого метода.

Перекрытия Ивар

Я мог бы попробовать объявляя Ивар в PasswordTextField называемого делегатом, но компилятор жалуется, что это дубликат декларации, потому что, конечно, уже есть Ивар называется делегатом суперкласса, так что не работает *.

Изменение суперкласс

я мог вернуться к TextField класс и переопределить делегата реализовать оба TextFieldDelegateиPasswordTextFieldDelegate, но это кажется грязным и говорит TextField, что он может послать PasswordTextFieldDelegate методы, которые из Конечно, это невозможно!

Я не пробовал этот, просто потому, что он, похоже, нарушает все разумные правила кодирования в книге.

Таким образом, должен быть какой-то способ сделать это, чтобы подкласс класса мог иметь собственный делегат, который является суб-делегатом делегата суперкласса и для всего этого хорошо сочетается, но я просто могу Не понимаю! Есть идеи?

(* В качестве побочного вопроса, я не понимаю, почему компилятор жалуется, когда PasswordTextField объявляет «дубликат» Ивар имени делегата, но не жалуется, когда TextField объявляет Ивар именем делегата, который предположительно является дубликатом UITextField 's свойство, называемое делегатом!)

+0

может быть им просто ударить в темноте .. но разве это не поможет, если вы просто повторно объявите @property вашего делегата как id и у вас есть собственный синтез? Я думаю, это сработает. mebbe плохо дать ему попробовать через некоторое время – govi

ответ

1

UITextField делегат ivar называется _delegate, а не делегат. Следовательно, почему вы уходите с объявлением его снова в TextField, но не в PasswordTextField.

Что касается проблемы наследования делегата. Я не уверен, что ObjectiveC поддерживает то, что вы хотите.

Возможно, вам просто нужно ввести идентификатор делегата, а не 'id <TextFieldDelegate>'. Затем вы можете переопределить setDelegate и убедиться, что делегат прошел в соответствии с ToProtocol. Тем не менее, вы потеряли бы свои проверки времени компиляции и проверили бы только время выполнения соответствийToProtocol

+0

Спасибо за разъяснение поведения _delegate. Я считал, что просто задаю тип как id - я забыл включить его в список возможных решений, но, как вы говорите, он теряет проверку времени компиляции, поэтому я подумал, что будет лучшее решение? –

+0

Ну, у вас не может быть лучшего из обоих миров (ну, я не думаю, что вы можете ... возможно, на некоторых языках лучше) ..... Я пришел с Java, и я пропустил сильную безопасность типа во-первых. Но Objective-C гораздо более гибкая, чем Java, что я могу жить с этими маленькими причудами - и наслаждаться всем остальным величие этого языка. Тем не менее, я использую только «id», если я действительно не могу дать что-то типа. – bandejapaisa

+0

Могу ли я получить пример кода? –

1

Итак, вот! работает .. и удается иметь предупреждения во время компиляции, а ..

SimpleParent.h

@protocol Parentprotocol <NSObject> 

@end 

@interface SimpleParent : NSObject { 
    id<Parentprotocol> obj; 
} 

@property (retain) id<Parentprotocol> obj; 

@end 

SimpleParent.m

#import "SimpleParent.h" 

@implementation SimpleParent 
@synthesize obj; 

@end 

SimpleChild.h

#import <Foundation/Foundation.h> 
#import "SimpleParent.h" 

@protocol SimpleChildProtocol <Parentprotocol> 


@end 

@interface SimpleChild : NSObject 

@property (assign) id<SimpleChildProtocol> obj; 

@end 

SimpleChild.m

#import "SimpleChild.h" 

@implementation SimpleChild 
@synthesize obj; 

@end 
+1

Это работает, пока SimpleChild не должен также наследовать от SimpleParent. Есть ли способ работать с ним, так что наследование работает как с классом, так и с протоколом одновременно? – jowie

1

Это довольно запутанный вопрос, так что простите меня, если я пропущу точку, но, похоже, ваши три разных уровня наследования имеют разные требования от их делегата, ergo каждый делегат должен будет соответствовать другому протоколу , так ли это было бы решением удержать делегата каждого уровня как иначе названного ivar и как другую ссылку?

Например, ваш базовый класс будет иметь свой delegate, который вы решили присвоить первому наследуемому подклассу. У этого есть собственный делегат, который называется level1delegate, а на следующем уровне ниже еще делегат, получивший название level2delegate. Конечно, вы могли бы установить все три из них одному и тому же объекту, если бы этот объект соответствовал всем трем протоколам.

В принципе, нет правила, согласно которому делегат должен называться «делегировать», поэтому не раздирайте себя, пытаясь не сломать его.

+0

Я думаю, он привык к другим языкам, которые позволят вам это сделать. Например, в Java я могу объявить переменную экземпляра определенного интерфейса (т. Е. Протокола) и в подклассе, я мог бы переопределить переменную экземпляра более специализированного типа (например, расширение интерфейса). Однако Java сильно статически напечатан – bandejapaisa

+0

Да, до разработки в Objective-C я был разработчиком Java! –

Смежные вопросы