在Objective C类别中使用Super?
-
05-07-2019 - |
题
我想覆盖Objective C类中我没有源代码的方法。
我已经研究过了,看来Categories应该允许我这样做,但我想在我的新方法中使用旧方法的结果,使用super来获得旧方法的结果。
每当我尝试这个时,我的方法会被调用,但是“超级”会被调用。是零...任何想法为什么?我正在使用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中看到的内容来看,我觉得应该允许这样做?
developer.apple.com上的类别文档: 当类别覆盖继承的方法时,该方法中的 像往常一样,类别可以调用 通过消息继承实现 超级但是,如果是一个类别 覆盖已经存在的方法 那里存在类别的类 无法调用原始文件 实施
解决方案
Categories扩展了原始类,但它们没有对它进行子类化,因此对 super
的调用找不到该方法。
您想要的是 Method Swizzling 。但请注意,您的代码可能会破坏某些内容。有一篇关于 The Scotacao由Scot Stevenson撰写的关于旧Objective-C运行时中的方法调配的文章, Matt Gallagher的Cocoa with Love 有一篇关于新目标中方法调配的文章-C 2.0运行时和它的简单替代。
或者,你可以继承类,然后使用子类或使用 +(void)poseAsClass:(Class)aClass
替换超类。 Apple写道:
由冒充类定义的方法 可以通过消息到
super
, 合并超类方法吧 覆盖。
请注意Apple已弃用Mac OS X 10.5中的 poseAsClass:
。
其他提示
如果你要对这个类进行编码,只需将选择器重命名为你的代码可以使用的东西,然后在 self
上调用原始选择器:
@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
NSString *result = [self fullPathFromRelativePath: relPath];
... do some stuff with the old result
return result;
}
如果要覆盖该类的此选择器的默认实现,则需要使用方法混合方法。
不完全属于类别,但通过在运行时动态添加方法有一种解决方法。 Samuel Dé fago在他的文章中描述了一种创建块IMP实现调用super的简洁方法,他的原始文章可以找到这里
相关代码是:
#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);