我想覆盖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);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top