通过ObjC类别重写一个方法并调用默认实现?
在使用类别时,可以使用自己的方式覆盖实现方法:
// 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
在包含类别networking结果“B”后调用方法“myMethod”。
myMethod类别实现调用原始类A myMethod最简单的方法是什么? 就我所知,您必须使用低级别的调用才能获得A类的原始方法钩子,然后调用它,但似乎在语法上会更简单。
如果你想要一个hackish的方式来做到这一点,涉及到的Objective-C运行时,你总是可以使用方法swizzling (在这里插入标准免责声明)。它将允许你存储不同的方法作为任意命名select器,然后交换运行时,因为你需要他们。
从comp.lang.objective-C FAQ列表 :“ 如果多个类别实现相同的方法呢?那么我们所知道的宇宙结构就不复存在了。实际上,这不是真的,但肯定会造成一些问题。当一个类实现了一个已经出现在一个类中的方法时(无论是通过另一个类,还是类的主@实现),该类的定义都会覆盖之前存在的定义,原来的定义不能再被Objective -C代码请注意,如果两个类别覆盖相同的方法,那么最后加载的是“胜利”,这在代码启动之前可能无法预测。
来自developer.apple.com :“当类别重写inheritance的方法时,类别中的方法可以像往常一样通过消息调用inheritance的实现,但是如果一个类别覆盖类别中已经存在的方法类,没有办法调用原来的实现“
看看我的文章有关在Mac开发人员库find的解决scheme: http : //codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html
基本上,和上面的方法Swizzling一样,有一个简单的例子:
#import <objc / runtime.h> @implementationtesting(logging) - (NSUInteger)logLength { NSUInteger长度= [自我logLength]; NSLog(@“日志logging:%d”,长度); 返回长度; } +(void)load { method_exchangeImplementations(class_getInstanceMethod(self,@selector(length)),class_getInstanceMethod(self,@selector(logLength))); } @结束
通过ConciseKit中包含的“helper”方法,你实际上调用了默认的实现…… 很奇怪,通过调用你的SWIZZLED实现..
你可以在+ (void) load
中调用+ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;
即,
[$ swizzleMethod:@selector(oldTired:) with:@selector(swizzledHotness:) in:self.class];
然后用混杂的方法,让我们假设它返回-(id)
..你可以做你的恶作剧,或者你是什么原因你摆在首位…然后,而不是返回一个对象,或self
,或不是。 。
return [self swizzledHotness:yourSwizzledMethodsArgument];
正如这里所解释的
在这个方法中,它看起来像我们再次调用相同的方法,导致和无尽的recursion。 但到了这一行时,这两个方法已经交换了。 所以当我们调用swizzled_synchronize时,实际上是调用原始方法。
它的感觉和看起来很奇怪,但是..它的工作原理。 这使您可以为现有方法添加无穷无尽的装饰,并且仍然“调用超级”(实际上是自己的),并从原始方法的手工中获益…即使没有访问原始来源。