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