Objective-C外部调用祖父类方法及iOS开发继承机制疑问
解决Objective-C中调用祖父类(A)方法的问题
嘿,我在Obj-C开发iPhone应用时也踩过继承的坑,确实和Java的套路不太一样!结合你描述的场景,我先拆解两种最可能的情况,再给你对应的解决方案:
情况1:类继承层级是A → B → C(A是B的父类,B是C的父类)
如果你的类结构是C继承B、B继承A,那正常情况下调用A的方法其实很直接——Obj-C的单继承会让子类自动继承所有父类(包括祖父类)的公开方法,直接用C的实例调用就行:
// 假设A有公开方法 - (void)grandpaMethod; C *myC = [[C alloc] init]; [myC grandpaMethod];
但如果B重写了A的这个方法,而你想强制调用A原本的实现(不是B重写后的版本),这时候不能像Java那样直接用super在外部调用,得换个方式:
- 最稳妥的做法是在B里封装一个专门的方法,用来调用A的实现:
之后在C外部就可以直接通过C实例调用这个封装方法:// 在B的.h文件里声明这个方法 - (void)callOriginalGrandpaMethod; // 在B的.m文件里实现 - (void)callOriginalGrandpaMethod { [super grandpaMethod]; // 这里的super会直接指向A的方法实现 }[myC callOriginalGrandpaMethod]; - 如果你实在不想修改B的代码,也可以用Runtime绕一下(但不推荐,会破坏封装):
#import <objc/runtime.h> C *myC = [[C alloc] init]; Method aMethod = class_getInstanceMethod([A class], @selector(grandpaMethod)); if (aMethod) { IMP imp = method_getImplementation(aMethod); void (*invokeMethod)(id, SEL) = (void (*)(id, SEL))imp; invokeMethod(myC, @selector(grandpaMethod)); }
情况2:C持有B传入的A类实例littleA
如果你的场景是B创建了A的实例littleA,然后把它传给了C(比如C有个属性存着这个实例),那调用A的方法就更简单了:
只要C把littleA的属性公开(或者提供一个访问方法),外部直接通过C实例拿到littleA再调用方法就行:
// 假设C的.h里声明了@property (nonatomic, strong) A *littleA; C *myC = [[C alloc] init]; [myC.littleA grandpaMethod];
如果littleA是C的私有属性(只在.m里声明),那可以在C里封装一个代理方法,间接调用:
// 在C的.h里声明 - (void)invokeLittleAGrandpaMethod; // 在C的.m里实现 - (void)invokeLittleAGrandpaMethod { [self.littleA grandpaMethod]; }
然后外部调用[myC invokeLittleAGrandpaMethod];就可以了。
聊聊Obj-C和Java继承的核心差异
你说Java的继承惯例不适用Obj-C,主要是这几个点:
- 动态 vs 静态绑定:Obj-C是动态语言,方法调用靠消息转发;Java是静态绑定,编译时就确定方法实现。这导致Obj-C调用父类方法的灵活性更高,但也容易出现消息转发的意外;
- super的本质不同:Java的
super是直接引用父类实例,而Obj-C的super只是指向当前实例的特殊指针,查找方法时会从父类开始找; - 优先组合而非继承:Obj-C里类别(Category)和组合的使用场景比继承更多,很多时候用类别扩展类或者用组合持有实例,比继承更优雅,也更灵活。
最后给个小建议:如果不是必须用多态的场景,优先用组合(比如C持有A的实例)替代继承,这样架构会更清晰,也避免继承带来的耦合问题~
内容的提问来源于stack exchange,提问作者Mengchen Lin
相关产品推荐
相关产品推荐

