Objective-C - Подкласс делегата в подклассе - PullRequest
4 голосов
/ 13 января 2012

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

Допустим, я создаю подкласс UITextField с именем TextField, который является моим собственным расширенным текстовым полем общего назначения. Теперь, чтобы обеспечить эту расширенную функциональность, в методе init для 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 соответствует только TextFieldDelegate, а не PasswordTextFieldDelegate, поэтому я не могу отправлять методы, подобные [delegate passwordIsSecure], потому что TextFieldDelegate не имеет такой метод.

Переопределение ivar

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

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

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

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

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

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

Ответы [ 3 ]

1 голос
/ 13 января 2012

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

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 голос
/ 13 января 2012

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

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

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

1 голос
/ 13 января 2012

UITextField делегат ivar называется _delegate, а не делегат. Поэтому вам и не нужно объявлять его снова в TextField, а не в PasswordTextField.

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

Возможно, вам просто нужно будет ввести свой идентификатор делегата вместо идентификатора id . Затем вы можете переопределить setDelegate и убедиться, что делегат передан в conformsToProtocol. Однако вы потеряете здесь проверки времени компиляции и будете иметь только проверку времени выполнения conformsToProtocol

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...