代码之家  ›  专栏  ›  技术社区  ›  Brad Parks

在目标c类中使用super?

  •  24
  • Brad Parks  · 技术社区  · 15 年前

    我想重写一个目标C类中没有源代码的方法。

    我已经研究过了,似乎categories应该允许我这样做,但是我想在我的新方法中使用旧方法的结果,使用super来获得旧方法的结果。

    不管我什么时候尝试,我的方法都会被调用,但是“super”是零…知道为什么吗?我正在用xcode 2.2sdk开发iphone。我确实在处理一个类的实例,该类的方法是一个实例方法。

    @implementation SampleClass (filePathResolver)
    -(NSString*) fullPathFromRelativePath:(NSString*) relPath
    {
        NSString *result = [super fullPathFromRelativePath: relPath];
    
      ... do some stuff with the old result
    
        return result;
    }
    

    注意和澄清:从我在苹果文档中可以看到的,我觉得这应该被允许吗?

    Categories docs at developer.apple.com: 当类别重写继承的方法时, 类别可以像往常一样调用 通过消息继承的实现 超级。但是,如果一个类别 重写已经 存在于类别的类中 无法调用原始的 实施。

    3 回复  |  直到 7 年前
        1
  •  29
  •   animaonline    7 年前

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

    你想要的叫做 Method Swizzling . 但是要注意你的代码可能会破坏一些东西。有篇关于 Theocacao written by Scot Stevenson 关于旧的objective-c运行时中的方法swizzing, Cocoa with Love by Matt Gallagher 有一篇关于在新的objective-c 2.0运行时中的方法swizzle的文章,以及一个简单的替换方法。

    或者,可以对类进行子类划分,然后使用子类或 + (void)poseAsClass:(Class)aClass 替换超类。苹果写道:

    由造型类定义的方法 通过消息可以 超级的 , 合并超类方法 重写。

    请注意,苹果已经弃用了 poseAsClass: 在Mac OS X 10.5中。

        2
  •  8
  •   Jason    15 年前

    如果您将对该类进行编码,只需将选择器重命名为代码可以使用的内容,并调用原始选择器 self :

    @implementation SampleClass (filePathResolver)
    -(NSString*) myFullPathFromRelativePath:(NSString*) relPath
    {
        NSString *result = [self fullPathFromRelativePath: relPath];
    
      ... do some stuff with the old result
    
        return result;
    }
    

    如果要重写该类的此选择器的默认实现,则需要使用 method swizzling 方法。

        3
  •  1
  •   Kamil.S    7 年前

    不完全在类别中,但有一个在运行时动态添加方法的解决方法。Samuel Dfago在他的文章中描述了一种创建块IMP实现方式的超级调用超级方法,可以找到他的原创文章。 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);