Лучший способ запретить другим программистам вызывать -init - PullRequest
39 голосов
/ 09 марта 2012

При проектировании иерархии классов иногда подкласс добавляет новый метод initWithSomeNewParam, и было бы желательно отключить вызовы старого метода init, унаследованного от суперкласса.

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

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

Если я прав, нет никакого способапометить метод как "частный".Итак, кроме добавления комментариев, есть ли способ сделать это?

Заранее спасибо.

Ответы [ 5 ]

106 голосов
/ 09 марта 2012

Вы можете явно пометить свой init как недоступный в заголовочном файле:

- (id) init __unavailable;

или:

- (id) init __attribute__((unavailable));

С более поздним синтаксисом вы даже можете указать причину:

- (id) init __attribute__((unavailable("Must use initWithFoo: instead.")));

Затем компилятор выдает ошибку (не предупреждение), если кто-то пытается ее вызвать.

4 голосов
/ 31 марта 2015

Чтобы добавить к тому, что написал @DarkDust, вы могли бы альтернативно использовать UNAVAILABLE_ATTRIBUTE

- (id)init UNAVAILABLE_ATTRIBUTE;

Это вызовет ошибку, когда пользователь попытается вызвать init в экземпляре этого класса.

1 голос
/ 09 марта 2012

Отметить это как устаревшее?Разработчики будут разработчиками, вы не можете остановить нас всех!; -)

Как пометить метод как устаревший в Objective-C 2.0?

0 голосов
/ 09 марта 2012

Вы можете сортировать пометить метод как "закрытый", определив личное расширение для вашего класса.

В вашем .h:

@interface MyClassName
- (void)initWithSomeNewParam:(id)param;

В вашем .m:

@interface MyClassName ()
- (void)init;
@end

Вы также можете добавить оператор NSLog, чтобы при запуске проекта с подключенным сеансом XCode они могли видеть вывод консоли, похожий на«Пожалуйста, не используйте init, используйте вместо этого initWithSomeNewParam:».Обратите внимание, что именно такой подход Apple исторически использовала для устаревших вызовов API (а также для обозначения устаревших в своих документах).

0 голосов
/ 09 марта 2012

initWith: Stuff и: OtherStuff никогда не должны быть больше, чем конструкторы удобства.

В том, что они фактически должны назвать

self = [self init];

if(self)
{
    self.stuff = Stuff;
    self.other = OtherStuff;
}

, поэтому [object init] всегда будет возвращать объект в предопределенном состоянии, а [object initWithStuff: stuff] будет возвращать объект в предопределенном состоянии с переопределением вещи.

По сути, я имею в виду, что это плохая практика - отговаривать [объект init], особенно когда кто-то подклассирует ваш подкласс в будущем… *

...