使用类别时,您可以使用自己的方法覆盖实现方法:
// 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
在包含类别之后调用方法“myMethod”将结果“B”。
myMethod的Category实现调用原始A类myMethod的最简单方法是什么?尽管我可以理解,你必须使用低级调用来获取A类的原始方法钩子并调用它,但似乎在语法上更容易实现这一点。
答案 0 :(得分:37)
如果你想要一个hackish方法,这涉及到使用objective-c运行时,你总是可以使用method swizzling(在这里插入标准的免责声明。)它将允许你将不同的方法存储为任意命名的选择器,然后在运行时根据需要交换它们。
答案 1 :(得分:19)
来自comp.lang.objective-C FAQ listing:“如果多个类别实现相同的方法怎么办?那么我们所知道的宇宙结构就不复存在了。实际上,这不是真的,但肯定当一个类实现一个已经出现在类中的方法(无论是通过另一个类,还是类'primary @implementation)时,该类的定义会覆盖以前存在的定义。原始定义不能Objective-C代码可以更长时间。请注意,如果两个类别覆盖相同的方法,则最后加载的是“胜利”,这可能无法在代码启动之前进行预测。“
从developer.apple.com:“当类别覆盖继承的方法时,类别中的方法可以像往常一样通过消息调用继承的实现到超级。但是,如果类别覆盖已存在的方法在类的类中,没有办法调用原始实现“
答案 2 :(得分:12)
查看我在Mac Developer Library上找到的解决方案的文章: http://codeshaker.blogspot.com/2012/01/calling-original-overridden-method-from.html
基本上,它与上面的方法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
答案 3 :(得分:1)
使用ConciseKit中包含的混合“帮助”方法,您实际上通过调用SWIZZLED实现来调用默认实现... 奇怪 ..
您在+ (void) load
中进行了设置,呼叫+ (BOOL)swizzleMethod:(SEL)originalSelector with:(SEL)anotherSelector in:(Class)klass;
,即
[$ swizzleMethod:@selector(oldTired:)
with:@selector(swizzledHotness:) in:self.class];
然后在混合的方法中..让我们假设它返回-(id)
..你可以做你的恶作剧,或者你在第一时间调整的任何理由......然后,而不是返回一个对象,或{ {1}},或者诸如此类..
self
在这个方法中,看起来我们再次调用相同的方法,导致无休止的递归。但到达此行时,两个方法已被交换。因此,当我们调用swizzled_synchronize时,我们实际上正在调用原始方法。
感觉和看起来很奇怪但是......它有效。这使您可以为现有方法添加无限的装饰,并且仍然可以“调用超级”(实际上是自己的)并获得原始方法的手工作用的好处......即使无法访问原始源。