我想覆盖Objective C类中我没有源代码的方法。
我已经研究过了,看来Categories应该允许我这样做,但是我想在我的新方法中使用旧方法的结果,使用super来获得旧方法的结果。< / p>
每当我尝试这个时,我的方法被调用,但“超级”是零...任何想法为什么?我正在使用XCode 2.2 SDK进行iPhone开发。我肯定在使用类的实例,类的方法是实例方法。
@implementation SampleClass (filePathResolver)
-(NSString*) fullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [super fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
注意和澄清:从我在Apple Docs中看到的内容来看,我觉得应该允许这样做吗?
Categories docs at developer.apple.com: 当类别覆盖继承的方法时,该方法中的 像往常一样,类别可以调用 通过消息继承实现 超级但是,如果是一个类别 覆盖已经存在的方法 那里存在类别的类 无法调用原始文件 实施
答案 0 :(得分:29)
Categories扩展了原始类,但是它们没有对它进行子类化,因此对super
的调用找不到该方法。
您想要的是Method Swizzling。但请注意,您的代码可能会破坏某些内容。在Theocacao written by Scot Stevenson中有一篇关于旧的Objective-C运行时中的方法Swizzling的文章,Cocoa with Love by Matt Gallagher在新的Objective-C 2.0运行时中有一篇关于Method Swizzling的文章,并且是一个简单的替代品。
或者,您可以继承该类,然后使用子类或使用+ (void)poseAsClass:(Class)aClass
替换超类。 Apple写道:
由冒充类定义的方法 可以通过
super
的消息, 合并超类方法吧 覆盖。
请注意,Apple已弃用Mac OS X 10.5中的poseAsClass:
。
答案 1 :(得分:8)
如果您要对此课程进行编码,只需将选择器重命名为您的代码可以使用的内容,然后在self
上调用原始选择器:
@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [self fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
如果要覆盖该类的此选择器的默认实现,则需要使用method swizzling方法。
答案 2 :(得分:1)
不完全属于类别,但通过在运行时动态添加方法有一种解决方法。 SamuelDéfago在他的文章中描述了一种创建块IMP实现调用super的简洁方法,他的原始文章可以找到here
相关代码是:
#import <objc/runtime.h>
#import <objc/message.h>
const char *types = method_getTypeEncoding(class_getInstanceMethod(clazz, selector));
class_addMethod(clazz, selector, imp_implementationWithBlock(^(__unsafe_unretained id self, va_list argp) {
struct objc_super super = {
.receiver = self,
.super_class = class_getSuperclass(clazz)
};
id (*objc_msgSendSuper_typed)(struct objc_super *, SEL, va_list) = (void *)&objc_msgSendSuper;
return objc_msgSendSuper_typed(&super, selector, argp);
}), types);