可可爷爷

3

能否访问对象的超类(或曾祖父)的超类方法?

例如:

GrandFatherObject : NSObject
SuperObject : GrandFatherObject
SelfObject : SuperObject

来自SelfObject:

- (void)overriddenMethod
{
  // For Self
  someCode();

  // For Parent
  [super overriddenMethod];

  // For GrandParent
  ???
}

我只能访问SelfObject(无法修改SuperObject或GrandFatherObject)


请参见https://dev59.com/V1DTa4cB1Zd3GeqPJHCB。 - Ben Zotto
3个回答

10

是的,你可以做到,但需要写更多的代码而不仅仅是调用super

或多或少,它会像这样:

#import <objc/runtime.h>

struct objc_super grandsuper;
grandsuper.receiver = self;
grandsuper.class = class_getSuperclass(class_getSuperclass([self class]));

//if _cmd has a non-struct return value:
id grandsuperReturnValue = objc_msgSendSuper(&grandsuper, _cmd, arg1, arg2, ...);

1
此外,由于通过 objc_msgSendSuper 发送的所有参数都使用 var_arg 列表,因此您方法的所有参数必须与可变参数列表兼容。例如,float 和 short 不起作用(在 var_arg 列表中,它们被提升为 double 和 int,无法被方法正确解析)。 - Matt Gallagher

5

为什么你想这样做?如果你认为这是必要的,那么你应该重新考虑你的类设计。当然,在父类的overriddenMethod实现中,你总是可以调用super

为了正确封装,子类不应该知道除了它们的父类以外的任何东西。否则,在继承层次结构中会有紧密的双向耦合。噩梦。


5
我同意这几乎永远不会成为必要的情况,但很容易想象何时可能需要这样做。例如,如果您正在编写一个类簇,并且父类簇类覆盖了-init方法以[self release]并返回一个适当子类型的新分配对象,则子类将 想调用 [super init],而是可能想调用[grandsuper init] - Dave DeLong
我最终想出了一种方法,而不使用“grandsuper”,但它仍然很复杂。我的特定情况是:我将一个NSView放入WebHTMLView中(我正在研究的一个小技巧,将cocoa视图放入WebView对象中),虽然它们进入得很好,看起来很棒,但我无法点击它们。这是因为WebHTMLView(一个私有类)重新定义了hitTest:所以我对WebView进行了子类化(自己),并覆盖了WebView的hitTest,检查它是否是我想要的命中(如果是),我将调用grandparent(NSView)hitTest,否则Parent(WebHTMLView)hitTest。虽然有些麻烦,但它确实有效。 - BadPirate

3

虽然使用objc_msgSendSuper()很有趣,但为什么不走捷径,在SelfObject实现中创建一个分类,例如:

@interface SuperObject (ForSelfObject)
  - (id)grandFatherOverridenMethod;
@end

@implementation SuperObject (ForSelfObject)
  - (id)grandFatherOverridenMethod {
    return [super overridenMethod];
  }
@end

你说你不能修改SuperObject,但这并不意味着你不能扩展它。我有没有忽略任何主要的缺点?


虚拟-1(实际上,我认为打负分有点过分了)。这将是一场灾难,因为您没有扩展超级对象,而是更改其部分行为。您可能正在绕过的方法中执行的操作对于其正确运行至关重要。 - JeremyP

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接