Переопределить метод в Objective c через категорию
В цели 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
Даже черт побери, если бы я сделал следующее:
// 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 является динамическим, это означает, что не имеет значения, импортируете вы или нет категорию. Объект получит сообщение и выполнит этот метод.
Категория переопределяет ваш метод. Это означает, что когда среда выполнения отправляет сообщение этому объекту, он всегда найдет переопределенный метод, независимо от того, что вы импортируете.
Если вы хотите игнорировать категорию, вам не следует ее компилировать, чтобы вы могли удалить категорию из исходников компилятора.
Альтернативой является создание подклассов.
Также прочитайте это:
Избегайте столкновений имен методов категорий
Поскольку методы, объявленные в категории, добавляются в существующий класс, вы должны быть очень осторожны с именами методов.
Если имя метода, объявленного в категории, совпадает с именем метода в исходном классе или методом в другой категории того же класса (или даже суперкласса), поведение не определено относительно того, какая реализация метода используется в во время выполнения. Это менее вероятно, если вы используете категории со своими собственными классами, но могут вызывать проблемы при использовании категорий для добавления методов в стандартные классы Cocoa или Cocoa Touch.
Так что в вашем случае у вас нет никаких проблем, потому что, как уже говорилось, это менее вероятно, произойдет с пользовательскими классами. Но вы должны определенно использовать подклассы вместо написания категории.
Obj-C позволяет вам добавлять методы в существующий класс, используя Категории. Поэтому, если вы добавляете метод в NSString, метод категоризации становится доступным для NSMutableString и всех классов, которые наследуют NSString или любые подклассы NSString.
Но вы должны избегать переопределения категории.
Вы не будете на 100% уверены, какой метод будет вызван. Это зависит от компилятора.
Из документации Apple.
Хотя язык Objective-C в настоящее время позволяет вам использовать категорию для переопределения методов, которые наследует класс, или даже методов, объявленных в интерфейсе класса, вам настоятельно не рекомендуется делать это. Категория не является заменой для подкласса. Есть несколько существенных недостатков в использовании категории для переопределения методов: когда категория переопределяет унаследованный метод, метод в категории может, как обычно, вызывать унаследованную реализацию через сообщение super. Однако если категория переопределяет метод, который существует в классе категории, нет способа вызвать исходную реализацию. Категория не может надежно переопределить методы, объявленные в другой категории того же класса. Эта проблема имеет особое значение, потому что многие классы Какао реализованы с использованием категорий. Определенный каркасом метод, который вы пытаетесь переопределить, сам может быть реализован в категории, и поэтому реализация, которая имеет приоритет, не определена. Само присутствие некоторых методов категории может вызвать изменения поведения во всех средах. Например, если вы переопределяете метод windowWillClose: делегат в категории в NSObject, все делегаты окна в вашей программе затем отвечают методом категории; поведение всех ваших экземпляров NSWindow может измениться. Категории, которые вы добавляете в каркасный класс, могут вызвать таинственные изменения в поведении и привести к сбоям.
Вы неявно включили код, определенный в категории, компилируя ее.
Если вы хотите избежать выполнения кода категории, вы должны удалить его из своей цели, удалив файл реализации категории. Вы можете сделать это из
Цель-> Фаза сборки-> Исходники компиляции
Тем не менее, вы никогда не должны использовать категорию для переопределения метода. Это очень плохая практика, и это не то, для чего нужны категории.