objective-c 通过 ObjC 类别覆盖方法并调用默认实现?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1085479/
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-09-03 21:51:57  来源:igfitidea点击:

Override a method via ObjC Category and call the default implementation?

objective-c

提问by Kendall Helmstetter Gelner

When using categories, you can override implementation methods with your own like so:

使用类别时,您可以使用自己的方法覆盖实现方法,如下所示:

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

//Category
@interface ClassA (CategoryB) 
- (NSString *) myMethod;
@end
@implementation ClassA (CategoryB)
- (NSString*) myMethod { return @"B"; }
@end

Calling the method "myMethod" after including the category nets the result "B".

在包含类别后调用方法“myMethod”会得到结果“B”。

What is the easiest way for the Category implementation of myMethod to call the original Class A myMethod? As near as I can figure out, you'd have to use the low level calls to get the original method hook for Class A and call that, but it seemed like there would be a syntactically easier way to do this.

myMethod 的 Category 实现调用原始 A 类 myMethod 的最简单方法是什么?就我所知,您必须使用低级调用来获取 A 类的原始方法挂钩并调用它,但似乎有一种语法上更简单的方法可以做到这一点。

采纳答案by cobbal

If you want a hackish way to do this that involves mucking with the objective-c runtime you can always use method swizzling(insert standard disclaimers here.) It will allow you to store the different methods as arbitrariliy named selectors, then swap them in at runtime as you need them.

如果你想要一种 hackish 的方式来做到这一点,涉及到与 Objective-C 运行时的混杂,你总是可以使用方法调配(在此处插入标准免责声明。)它允许你将不同的方法存储为任意命名的选择器,然后将它们交换在运行时,您需要它们。

回答by Oren Trutner

From comp.lang.objective-C FAQ listing: "What if multiple categories implement the same method?Then the fabric of the Universe as we know it ceases to exist. Actually, that's not quite true, but certainly some problems will be caused. When a category implements a method which has already appeared in a class (whether through another category, or the class' primary @implementation), that category's definition overwrites the definition which was previously present. The original definition can no longer be reached by the Objective-C code. Note that if two categories overwrite the same method then whichever was loaded last "wins", which may not be possible to predict before the code is launched."

来自comp.lang.objective-C FAQ 列表:“如果多个类别实现相同的方法怎么办?那么我们所知道的宇宙结构将不复存在。实际上,这并不完全正确,但肯定会引起一些问题。当一个类别实现一个已经出现在一个类中的方法时(无论是通过另一个类别,还是该类的主要@implementation),该类别的定义会覆盖之前存在的定义。原始定义无法再被目标访问-C 代码。请注意,如果两个类别覆盖相同的方法,则最后加载的那个“获胜”,这在代码启动之前可能无法预测。

From developer.apple.com: "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 already existed in the category's class, there is no way to invoke the original implementation"

来自developer.apple.com:“当类别覆盖继承的方法时,类别中的方法可以像往常一样通过向 super 发送消息调用继承的实现。但是,如果类别覆盖了类别中已经存在的方法类,没有办法调用原始实现”

回答by Andras

Check out my article about a solution found on the Mac Developer Library: http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html

查看我关于在 Mac 开发人员库中找到的解决方案的文章:http: //codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html

Basically, it's the same as the above Method Swizzling with a brief example:

基本上,它与上面的 Method Swizzling 相同,只是一个简单的例子:

#import <objc/runtime.h>

@implementation Test (Logging)

- (NSUInteger)logLength {
    NSUInteger length = [self logLength];
    NSLog(@"Logging: %d", length);
    return length;
}

+ (void)load {
    method_exchangeImplementations(class_getInstanceMethod(self, @selector(length)), class_getInstanceMethod(self, @selector(logLength)));
}

@end

回答by Alex Gray

With the swizzling "helper" methods included in ConciseKit, you actually call the default implementation… weirdly enough.. by calling your SWIZZLED implementation..

使用ConciseKit 中包含的swizzling“helper” 方法,您实际上调用了默认实现……很奇怪……通过调用您的 SWIZZLED 实现……

You set it up in + (void) load, calling + (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;, i.e.

你设置它+ (void) load,调用+ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;,即

[$ swizzleMethod:@selector(oldTired:) 
            with:@selector(swizzledHotness:) in:self.class];

and then in the swizzled method.. let's suppose it returns -(id).. you can do your mischief, or whatever reason you are swizzling in the first place… and then, instead of returning an object, or self, or whatnot..

然后在 swizzled 方法中.. 假设它返回-(id).. 你可以做你的恶作剧,或者任何你首先 swizzled 的原因......然后,而不是返回一个对象,或者self,或者诸如此类的......

return [self swizzledHotness:yourSwizzledMethodsArgument];

As explained here…

正如这里所解释的……

In this method, it looks like we're calling the same method again, causing and endless recursion. But by the time this line is reached the two method have been swapped. So when we call swizzled_synchronize we're actually calling the original method.

在这个方法中,看起来我们又在调用同一个方法,导致无限递归。但是当到达这条线时,这两种方法已经互换了。所以当我们调用 swizzled_synchronize 时,我们实际上是在调用原始方法。

It feels and looks odd, but.. it works. This enables you to add endless embellishments to existing methods, and still "call super" (actually self) and reap the benefits of the original method's handiwork… even without access to the original source.

感觉和看起来很奇怪,但是......它有效。这使您能够为现有方法添加无穷无尽的修饰,并且仍然“调用 super”(实际上是 self)并获得原始方法的手工成果……即使无法访问原始源。