Что происходит, если две категории 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, но я не уверен, как ли это, гарантируют, произойдет, или просто одна определенная разновидность неопределенного поведения.

13
задан e.James 11 July 2010 в 18:07
поделиться

2 ответа

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

12
ответ дан 1 December 2019 в 17:51
поделиться

В продолжение ответа drawonward:

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

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

Итак:

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

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

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

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

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

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

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

34
ответ дан 1 December 2019 в 17:51
поделиться