Переопределение унаследованных типов в Objective-C - PullRequest
1 голос
/ 22 июня 2010

Это, вероятно, распространенный вопрос Objective-C, о котором сообщают Java-кодеры, но я не знаю, как его назвать или как искать ответ. Допустим, у меня есть класс и другой класс, который расширяет его:

AbstractModel

@interface AbstractModel {
}

ModelImpl

@interface ModelImpl : AbstractModel {
}

Отдельно от них у меня есть еще два класса, снова один расширяющий другой:

ControllerA

@interface ControllerA {
    AbstractModel *foo;
}

@property (nonatomic, retain) AbstractModel *foo;

ControllerB

@interface ControllerB : ControllerA {
}

Я хочу сказать, что foo в ControllerA может содержать AbstractModel или любой из его подтипов. Тем не менее, компилятор выдает мне предупреждение, если я пытаюсь сохранить в нем что-либо, кроме AbstractModel. (Конечно, я понимаю, что классы не могут действительно быть абстрактными в ObjC, но помилуют меня.)

Я также хотел бы иметь возможность "заблокировать" свойство foo в определенных подклассах. Я хотел бы сказать, что foo в ControllerB может содержать только ModelImpl4, например. Это возможно?

Какова общепринятая передовая практика Objective C для решения этого типа проблемы? Использует ли наследование таким образом - или для достижения этой цели - просто не очень хорошая идея в Objective-C?

Ответы [ 2 ]

3 голосов
/ 22 июня 2010

Во-первых, я хочу понять это:

Однако компилятор выдает мне предупреждение, если я пытаюсь сохранить в нем что-либо, кроме AbstractModel.

Это не имеет смысла.Вы должны быть в состоянии назначить подклассы от AbstractModel до foo без проблем.Какую проблему вы видите?

Далее, то, что вы описываете, не переопределяет, это перегрузка.Вы пытаетесь изменить тип возвращаемого значения метода, и вы не можете сделать это в ObjC.Есть очень хорошие решения этой проблемы, но это в некоторой степени зависит от вашей реальной цели.

  • Сначала вы можете избавиться от -foo в ControllerA.Если ControllerA на самом деле абстрактно, то, возможно, лучше его не иметь.Если ControllerA является абстрактным, я определенно рекомендую вам избавиться от foo ивара в этом слое.Вы должны поместить ivars в подклассы.

  • Кроме того, вы можете добавить типизированные методы к подклассам.Например, ControllerB будет иметь метод -modelBFoo в дополнение к -foo, который он наследует.Эти методы будут идентичны;у них просто будут разные типы возвращаемых значений, что позволит правильно набирать текст для всех вызывающих абонентов.

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

1 голос
/ 22 июня 2010

Да.Самый простой способ решить первую проблему - просто игнорировать предупреждения компилятора.Это будет работать во время выполнения.Если вам не нравятся предупреждения, вы можете набрать:

foo = (AbstractModel *)thisIsAModelImpl;

Затем, чтобы «заблокировать» его для ControllerB, вы просто добавили бы эту строку в ваш .h файл

ModelImpl *foo;

И вы хотели бы переопределить (переопределить) любые методы, имеющие дело с foo в ControllerB.

Редактировать: Ради ясности, это то, что я имею в виду под переопределением.

Если у вас есть методы (в ControllerA)

-setFoo:(AbstractModel *)newModel;
-(AbstractModel *)foo;

Вы бы изменили эти строки на (в ControllerB)

-setFoo:(ModelImpl*)newModel;
-(ModelImpl*)foo;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...