Как избежать случайного переопределения подкласса закрытого метода суперкласса

Я пишу библиотеку, которая потенциально будет использоваться людьми, которые не являются мной.

Допустим, я пишу класс:

InterestingClass.h

@interface InterestingClass: NSObject
- (id)initWithIdentifier:(NSString *)Identifier;
@end

InterestingClass.m

@interface InterestingClass()
- (void)interestingMethod;
@end

@implementation InterestingClass
- (id)initWithIdentifier:(NSString *)Identifier {
  self = [super init];
  if (self) {
    [self interestingMethod];
  }
  return self;
}

- (void)interestingMethod {
  //do some interesting stuff
}
@end

Что делать, если кто-то позже использует библиотеку и решит создать подкласс InterestingClass?:

InterestingSubClass.h

@interface InterestingSubClass: InterestingClass
@end

InterestingSubClass.m

@interface InterestingSubClass()
- (void)interestingMethod;
@end

@implementation InterestingSubClass
- (void)interestingMethod {
  //do some equally interesting, but completely unrelated stuff
}
@end

Будущий пользователь библиотеки может видеть из открытого интерфейса, что initWithIdentifier это метод суперкласса. Если они переопределят этот метод, они, вероятно, предположат (правильно), что superclass метод должен быть вызван в реализации подкласса.

Однако что, если они определяют метод (в частном интерфейсе подкласса), который случайно имеет то же имя, что и несвязанный метод в "частном" интерфейсе суперкласса? Без чтения частного интерфейса суперкласса они не узнают, что вместо создания нового метода они также что-то переопределили в суперклассе. Реализация подкласса может закончиться неожиданным вызовом, и работа, которую суперкласс ожидает выполнить при вызове метода, не будет выполнена.

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

Альтернативно, есть ли способ ограничить вызов методов из моего суперкласса, чтобы я мог быть уверен, что реализация суперкласса будет вызываться вместо реализации подкласса?

2 ответа

Решение

AFAIK, лучшее, на что ты можешь надеяться, это объявить, что переопределения должны вызывать super. Вы можете сделать это, определив метод в суперклассе как:

- (void)interestingMethod NS_REQUIRES_SUPER;

Это будет отмечать во время компиляции любые переопределения, которые не вызывают super.

Для каркасного кода простой способ справиться с этим - просто дать всем вашим приватным методам частный префикс.

Вы часто будете замечать в следах стека, что фреймворки Apple вызывают частные методы, часто начинающиеся с нижней черты _,

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

NB
Не начинайте свои методы с префикса под строкой, так как это соглашение уже зарезервировано

Другие вопросы по тегам