通过类别覆盖Objective c中的方法

Ale*_*der 20 objective-c categories ios

以下是在目标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
Run Code Online (Sandbox Code Playgroud)

问题是,如果我只是导入ClassA.h并发送消息

[myClassA myMethod]; //returns B
Run Code Online (Sandbox Code Playgroud)

这为什么会回归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
Run Code Online (Sandbox Code Playgroud)

并调用mySecondMethod:

ClassA *a = [[ClassA alloc] init];
NSLog(@"%@",[a myMethod]);
Run Code Online (Sandbox Code Playgroud)

结果仍然是B虽然没有人知道(由于没有导入)类别实现?!

我除外,只有B在我输入类别时返回...

所以任何提示都值得赞赏.

Ram*_*uri 40

Objective-C消息传递是动态的,这意味着无论您是否导入类别都无关紧要.该对象将接收消息并执行该方法.

该类别覆盖了您的方法.这意味着当运行时向该对象发送消息时,无论您导入什么内容,都将始终找到重写的方法.

如果要忽略某个类别,则不应编译它,因此可以从编译器源中删除该类别.
另一种方法是子类化.

另请阅读:

避免使用类别方法名称冲突

因为在类别中声明的方法被添加到现有类中,所以您需要非常小心方法名称.

如果在类别中声明的方法的名称与原始类中的方法相同,或者在同一个类(或甚至是超类)上的另一个类别中的方法相同,则关于在哪个方法实现中使用哪个方法实现的行为是未定义的.运行.如果您使用具有自己类的类别,则不太可能成为问题,但在使用类别向标准Cocoa或Cocoa Touch类添加方法时可能会导致问题.

因此,在您的情况下,您没有遇到任何问题,因为如上所述,用户定义的类不太可能发生这种情况.但你绝对应该使用子类而不是写一个类别.


Ano*_*dya 10

Obj-C允许您使用类别向现有类添加方法.因此,如果向NSString添加方法,则NSMutableString和继承NSString或NSString的任何子类的所有类都可以使用分类方法.

但是你应该避免覆盖该类别.

您不会100%确定将调用哪种方法.这取决于编译器.

来自Apple文档.

尽管Objective-C语言当前允许您使用类别来覆盖类继承的方法,甚至是类接口中声明的方法,但强烈建议您不要这样做.类别不能替代子类.使用类别覆盖方法有几个明显的缺点:当类别覆盖继承的方法时,类别中的方法可以像往常一样通过消息调用继承的实现到超级.但是,如果类别覆盖类别类中存在的方法,则无法调用原始实现.类别无法可靠地覆盖在同一类的另一个类别中声明的方法.这个问题特别重要,因为许多Cocoa类都是使用类别实现的.您尝试覆盖的框架定义方法本身可能已在类别中实现,因此未定义优先级高的实现.某些类别方法的存在可能会导致所有框架的行为更改.例如,如果您在NSObject上的类别中覆盖windowWillClose:delegate方法,则程序中的所有窗口委托都会使用category方法进行响应.您所有NSWindow实例的行为可能会发生变化.您在框架类上添加的类别可能会导致行为发生神秘变化并导致崩溃.