24

我想覆盖一个我没有源代码的 Objective C 类中的方法。

我已经调查过了,似乎类别应该允许我这样做,但我想在我的新方法中使用旧方法的结果,使用 super 来获取旧方法的结果。

每当我尝试这个时,我的方法都会被调用,但是“super”是 nil ......知道为什么吗?我正在使用 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 上的类别文档: 当类别覆盖继承的方法时,类别中的方法可以像往常一样通过向 super 发送消息来调用继承的实现。但是,如果一个类别覆盖了该类别的类中已经存在的方法,则无法调用原始实现。

4

3 回答 3

29

类别扩展了原始类,但它们没有子类化它,因此调用super找不到方法。

您想要的称为Method Swizzling。但请注意,您的代码可能会破坏某些东西。有一篇由 Scot Stevenson 撰写的关于 Theocacao的文章,关于旧的 Objective-C 运行时中的 Method Swizzling,Matt Gallagher 的 Cocoa with Love有一篇关于新的 Objective-C 2.0 运行时中的 Method Swizzling 的文章和一个简单的替代品。

或者,您可以子类化该类,然后使用子类或使用+ (void)poseAsClass:(Class)aClass替换超类。苹果写道:

由 POS 类定义的方法可以通过向 发送消息super,合并它覆盖的超类方法。

请注意,Apple 已poseAsClass:在 Mac OS X 10.5 中弃用。

于 2009-09-10T12:47:07.847 回答
8

如果您要针对此类进行编码,只需将选择器重命名为您的代码可以使用的名称,然后在以下位置调用原始选择器self

@implementation SampleClass (filePathResolver)
-(NSString*) myFullPathFromRelativePath:(NSString*) relPath
{
    NSString *result = [self fullPathFromRelativePath: relPath];

  ... do some stuff with the old result

    return result;
}

如果要为该类覆盖此选择器的默认实现,则需要使用方法调配方法。

于 2009-09-10T13:16:00.070 回答
1

不完全属于类别,但有一种解决方法是在运行时动态添加该方法。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);
于 2017-04-21T11:09:33.610 回答