Переопределение метода в Objective c через категорию

в objective c работает следующее:

// Base Class in ClassA.h and ClassA.m
@interface ClassA : NSObject 
- (NSString *) myMethod;
@end
@implementation ClassA
- (NSString*) myMethod { return @"A"; }
@end

//Category in ClassA+CategoryB.h and ClassA+CategoryB.m
@interface ClassA (CategoryB) 
- (NSString *) myMethod;
@end
@implementation ClassA (CategoryB)
- (NSString*) myMethod { return @"B"; }
@end

вопрос в том, если я просто импортирую ClassA.h и отправить сообщение

[myClassA myMethod]; //returns B

почему это возвращение B? Я не импортирую ClassA + CategoryB

даже futhrer, если бы я сделал следующее:

// Base Class in ClassA.h and ClassA.m
@interface ClassA : NSObject 
- (NSString *) myMethod;
- (NSString *) mySecondMethod;
@end
@implementation ClassA
- (NSString*) myMethod { return @"A"; }
- (NSString *) mySecondMethod { return [self myMethod]; }
@end

//Category in ClassA+CategoryB.h and ClassA+CategoryB.m
@interface ClassA (CategoryB) 
- (NSString *) myMethod;
@end
@implementation ClassA (CategoryB)
- (NSString*) myMethod { return @"B"; }
@end

и вызовите mySecondMethod:

ClassA *a = [[ClassA alloc] init];
NSLog(@"%@",[a myMethod]);

результат все равно будет B хотя никто не знает (из-за отсутствия импорта) из категории реализация?!

Я говорю только вернуть Bесли бы я импортировал категорию...

так что любые подсказки оценили.

3 ответов


Objective-C messaging является динамическим, это означает, что не имеет значения, импортируете вы категорию или нет. Объект получит сообщение и выполнит этот метод.

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

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

также прочитайте это:

Избегайте Столкновений Имен Методов Категорий

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

Если имя метода, объявленного в категории, совпадает с именем метода в исходном классе или метода в другой категории в том же классе (или даже суперкласс), поведение не определено, какая реализация метода используется во время выполнения. Это менее вероятно, если вы используете категории с вашими собственными классами,но может вызвать проблемы при использовании категорий для добавления методов к стандартным классам Cocoa или Cocoa Touch.

поэтому в вашем случае у вас нет никаких проблем, потому что, как указано, это менее вероятно, произойдет с пользовательскими классами. Но!--11-->вы определенно должны использовать наследование, а не писать категория.


Obj-C позволяет добавлять методы в существующий класс с помощью категорий. Поэтому, если вы добавляете метод в NSString, метод categoriesed доступен для NSMutableString и всех классов, которые наследуют NSString или любые подклассы NSString.

но вы должны избегать переопределения категории.

вы не будете на 100% уверены, какой метод будет вызван. Это зависит от компилятора.

Из Документации Apple.

хотя Язык Objective-C в настоящее время позволяет использовать категорию для переопределения методов, наследуемых классом, или даже методов, объявленных в интерфейсе класса. Категория не является заменой подкласса. Существует несколько существенных недостатков в использовании категории для переопределения методов: когда категория переопределяет унаследованный метод, метод в категории может, как обычно, вызвать унаследованную реализацию через сообщение super. Однако, если категория переопределяет метод, который существует в классе категории, нет способа вызвать исходную реализацию. Категория не может надежно переопределять методы, объявленные в другой категории того же класса. Эта проблема имеет особое значение, поскольку многие классы какао реализуются с использованием категорий. Определяемый платформой метод, который вы пытаетесь переопределить, может быть реализован в категории, и поэтому приоритет реализации не определен. Само присутствие некоторых методы категорий могут вызывать изменения поведения во всех фреймворках. Например, если переопределить метод windowWillClose: delegate в категории В NSObject, все делегаты окна в программе будут отвечать с помощью метода category; поведение всех экземпляров NSWindow может измениться. Категории, добавляемые в класс framework, могут вызывать таинственные изменения в поведении и приводить к сбоям.


вы неявно включили код, определенный в категорию, путем его компиляции.

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

Target - >Build Phase - >Compile Sources

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