Подтвердить что ты не робот

Переопределить метод в 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

Даже 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, если я импортировал категорию...

Таким образом, любые намеки были оценены.

4b9b3361

Ответ 1

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

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

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

Также читайте это:

Избегайте столкновений имени класса метода

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

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

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

Ответ 2

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

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

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

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

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

Ответ 3

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

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

Target- > Build Phase- > Compile Sources

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