Что произойдет, если две категории ObjC переопределяют один и тот же метод?
Я знаю несколько правил относительно категорий Objective-C:
- Методы категорий не должны переопределять существующие методы (класс или экземпляр).
- Две разные категории, реализующие один и тот же метод для одного и того же класса, приведут к поведению undefined
Я хотел бы знать, что происходит, когда я переопределяю один из моих собственных методов категорий в той же категории. Например:
@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 имеет приоритет, но я не уверен, что это гарантировано, или просто один конкретный вкус поведения undefined.
Ответы
Ответ 1
Каждый метод каждого класса имеет реализацию. Категория добавляет или заменяет метод для определенного класса. Это означает, что поведение, которое вы видите, где MyClass имеет один foo
, а NSView имеет другой foo
, хорошо определен. Любой экземпляр MyClass будет иметь другой foo
, чем любой экземпляр NSView, который не является MyClass, как если бы foo
был определен в основной реализации, а не в категории. Вы даже можете вызвать [super foo]
из MyClass для доступа к foo
, определенному для NSView.
Ответ 2
Чтобы продолжить на обратный ответ:
Это вопрос иерархии. Категории - это всего лишь средство организации исходных файлов. При компиляции все методы класса, включая те, которые определены в любой категории, попадают в один и тот же файл.
Все, что вы могли бы сделать в обычном интерфейсе класса, который вы можете сделать в категории, и все, что вы не должны делать в обычном интерфейсе класса, вы не должны делать в категории.
Итак:
Методы категорий не должны переопределять существующие методы (класс или экземпляр)
Вы можете использовать методы, определенные в интерфейсе обычного класса, для переопределения методов наследуемых, чтобы вы могли переопределить унаследованные методы в категории.
Тем не менее, вы никогда бы не попытались использовать два идентичных определения метода в одном и том же обычном интерфейсе, поэтому никогда не следует иметь метод в категории с тем же именем, что и метод в обычном интерфейсе или другой категории на одном и том же класс. Поскольку все определения методов заканчиваются в одном и том же скомпилированном файле, они, очевидно, сталкиваются.
Две различные категории, реализующие тот же метод приводит к undefinedПоведение
Это нужно переписать, чтобы сказать: "Две разные категории, реализующие один и тот же метод для одного и того же класса, приводят к поведению undefined". Опять же, поскольку все методы для любого одного класса попадают в один и тот же файл, имея два метода в одном классе, очевидно, вызовет странность.
Вы можете использовать категории для предоставления методов, которые переопределяют методы суперкласса, потому что класс и его суперкласс - это два разных класса.
Если вы когда-либо путались о том, приведет ли категория к проблеме, просто спросите себя: "Будут ли методы в категории работать, если я скопировал и вложил их все в файлы".h/.m "класса?" Если ответ "да", значит, вы поняли. Если "нет", тогда у вас проблемы.