Что произойдет, если две категории ObjC переопределят один и тот же метод?

Я знаю пару правил относительно категорий Objective-C:

  1. Методы категории не должны переопределять существующие методы (класс или экземпляр)
  2. Две разные категории, реализующие один и тот же метод для одного и того же класса, приведут к неопределенному поведению

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

@interface NSView (MyExtensions)
- (void)foo; // NSView category implementation
@end

@interface MyClass : NSView
{ }
@end

@interface MyClass (MyExtensions)
- (void)foo; // MyClass category implementation
@end

После определения этих интерфейсов, какой метод будет выполнен при запуске следующего кода?

MyClass * instance = [[MyClass alloc] initWith...];
[instance foo];
[instance release];

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


person e.James    schedule 11.07.2010    source источник


Ответы (2)


У каждого метода каждого класса есть реализация. Категория добавляет или заменяет метод для определенного класса. Это означает, что поведение, которое вы видите, когда MyClass имеет один foo, а NSView - другой foo, четко определено. Любой экземпляр MyClass будет иметь foo отличный от любого экземпляра NSView, который не является MyClass, как если бы foo был определен в основной реализации, а не в категории. Вы даже должны иметь возможность вызывать [super foo] из MyClass для доступа к foo, определенному для NSView.

person drawnonward    schedule 11.07.2010
comment
Правильно ли переопределить метод категории, объявленный и реализованный в категории суперкласса? - person BergP; 19.03.2013

Чтобы продолжить ответ на этот вопрос:

Дело в иерархии. Категории на самом деле являются просто средством организации исходных файлов. При компиляции все методы класса, включая методы, определенные в любой категории, попадают в один и тот же файл.

Все, что вы можете делать в интерфейсе обычного класса, вы можете делать в категории, и все, что вы не должны делать в интерфейсе обычного класса, вы не должны делать в категории.

So:

Методы категории не должны переопределять существующие методы (класс или экземпляр)

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

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

Две разные категории, реализующие один и тот же метод, приводят к неопределенному поведению

Это следует переписать так, чтобы было сказано: «Две разные категории, реализующие один и тот же метод для одного и того же класса, приводят к неопределенному поведению». Опять же, поскольку все методы для любого одного класса попадают в один и тот же файл, наличие двух методов в одном классе, очевидно, вызовет странность.

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

Если вы когда-нибудь сомневались в том, вызовет ли категория проблему, просто спросите себя: «Будут ли работать методы в категории, если я скопирую и вставлю их все в файлы .h / .m класса?» Если ответ «да», то вам ничего не известно. Если «нет», значит, у вас проблемы.

person TechZen    schedule 11.07.2010
comment
+1 Спасибо. Это очень хорошее описание. Я также изменил формулировку правила № 2, чтобы она соответствовала вашей. - person e.James; 11.07.2010