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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14259517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 21:48:42  来源:igfitidea点击:

Override a method in Objective c via category

iosobjective-ccategories

提问by Alexander

The following is working in 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

The question is, if I am just importing ClassA.h and send the message

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

[myClassA myMethod]; //returns B

why is this returning B? I am not importing ClassA+CategoryB

为什么这回来了B?我没有导入 ClassA+CategoryB

Even futhrer, if I did the following:

更进一步,如果我执行以下操作:

// 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

and call mySecondMethod:

并调用 mySecondMethod:

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

the result will still be Balthough nobody knows (due to no import) of the category implementation?!

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

I'd excepted, only to return Bif I was importing the category...

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

So any hints appreciated.

所以任何提示表示赞赏。

回答by Ramy Al Zuhouri

Objective-C messaging is dynamic, this means that it doesn't matter if you import or not the category. The object will receive the message and execute that method.

Objective-C 消息传递是动态的,这意味着您是否导入类别并不重要。该对象将接收消息并执行该方法。

The category is overriding your method. This means that when the runtime sends a message to that object, will always find the overridden method, no matter what you import.

该类别正在覆盖您的方法。这意味着当运行时向该对象发送消息时,无论您导入什么,都将始终找到被覆盖的方法。

If you want to ignore a category you shouldn't compile it, so you could remove the category from the compiler sources.
An alternative is subclassing.

如果您想忽略某个类别,则不应对其进行编译,因此您可以从编译器源代码中删除该类别。
另一种方法是子类化。

Also read this:

另请阅读:

Avoid Category Method Name Clashes

Because the methods declared in a category are added to an existing class, you need to be very careful about method names.

If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. This is less likely to be an issue if you're using categories with your own classes, but can cause problems when using categories to add methods to standard Cocoa or Cocoa Touch classes.

避免类别方法名称冲突

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

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

So in your case you haven't got any problem because as stated, this is less likely to happen with user defined classes. But you should definitely use subclassing instead of writing a category.

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

回答by Anoop Vaidya

Obj-C allows you to add methods to an existing class using Categories. So if you add a method to NSString, the categoriesed method is available to NSMutableString and all classes which inherits NSString or any subclasses of NSString.

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

But you should avoid to Override the category.

但是您应该避免覆盖类别。

You will not be 100% sure which method will be called. It depends on compiler.

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

From Apple Documentation.

来自苹果文档。

Although the Objective-C language currently allows you to use a category to override methods the class inherits, or even methods declared in the class interface, you are strongly discouraged from doing so. A category is not a substitute for a subclass. There are several significant shortcomings to using a category to override methods: When a category overrides an inherited method, the method in the category can, as usual, invoke the inherited implementation via a message to super. However, if a category overrides a method that exists in the category's class, there is no way to invoke the original implementation. A category cannot reliably override methods declared in another category of the same class. This issue is of particular significance because many of the Cocoa classes are implemented using categories. A framework-defined method you try to override may itself have been implemented in a category, and so which implementation takes precedence is not defined. The very presence of some category methods may cause behavior changes across all frameworks. For example, if you override the windowWillClose: delegate method in a category on NSObject, all window delegates in your program then respond using the category method; the behavior of all your instances of NSWindow may change. Categories you add on a framework class may cause mysterious changes in behavior and lead to crashes.

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

回答by Gabriele Petronella

You implicitly included the code defined in the category by compiling it.

您通过编译隐式包含了类别中定义的代码。

If you want to avoid the category code to be executed you should remove it from your target, by removing the category implementation file. You can do that from

如果您想避免执行类别代码,您应该通过删除类别实现文件将其从目标中删除。你可以从

Target->Build Phase->Compile Sources

目标->构建阶段->编译源

That said, you should neveruse a category to override a method. That's a very bad practice and it's not what categories are for.

也就是说,您永远不应该使用类别来覆盖方法。这是一个非常糟糕的做法,它不是类别的用途。