在Objective C类别中使用Super?

时间:2009-09-10 12:40:46

标签: objective-c categories super

我想覆盖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:   当类别覆盖继承的方法时,该方法中的   像往常一样,类别可以调用   通过消息继承实现   超级但是,如果是一个类别   覆盖已经存在的方法   那里存在类别的类   无法调用原始文件   实施

3 个答案:

答案 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);