关于父对象的init方法

Parent.h(扩展NSObject)是这样的:

@implementation InTParent -(id)init { NSLog(@"Parent init method"); if (self = [super init]) { ; } return self; } -(id)initWithName:(NSString*)name; { NSLog(@"Parent initWithName method"); if (self = [self init]) { ; } return self; } 

Son.h(扩展Parent)像这样:

 @implementation InTSon -(id)init { NSLog(@"Son init method"); if (self = [super init]) { ; } return self; } -(id)initWithName:(NSString*)name; { NSLog(@"Son initWithName method"); if (self = [super initWithName:name]) { ; } return self; } 

我用这个: IntSon *_son = [[IntSon alloc] initWithName:@"asd"];

为什么输出是:Son initWithName方法 – > Parent的initWithName方法 – > Son的init方法 – > Parent的init方法

但在Java中,也许这样:Son initWithName方法 – > Parent initWithName方法 – > Parent init方法

请帮帮我!

为了理解这个行为,你必须了解Objective-C消息调度的工作原理。 这是一个很好的例子来说明这一点。

在高层次上,无论何时您调用任何对象上的方法,Objective-C运行时都会查找提供了派生最多(类层次结构中最深的)类的实现。 如果它没有find它,它将会进入下一个派生的,等等,直到NSObject 。 它第一次发现一个匹配select器(方法名称,大致)的实现,它将执行该实现。 当你调用super ,你正在指定发送一个消息给下一个派生类的实现。

因此,在你的代码中,你调用InTSon类的alloc ,它返回IntSon一个实例,将isa指针设置为类对象InTSonisa指针是在升序类层次结构的过程中如何查找方法实现的。

所以在你有一个InTSon实例之后,你可以调用initWithName: InTSon然后它检查isa指向的类( InTSon是这个方法的一个实现,它发现它,执行它,导致你的第一个输出:

"Son initWithName method"

之后,立即调用该方法的超类实现,该方法在InTParent中查找initWithName:实现initWithName:并执行该代码,从而生成第二个输出:

Parent initWithName method

现在,在这里你看到了一个偏离Java的地方 – 你自己调用init 。 但是, self是指向InTSon实例的指针。 所以当运行时parsing这个消息的时候,它首先在InTSon类中实现init 。 当然,它find它,并执行该方法的代码,它给你你的第三个输出, Son init method 。 接下来调用super,它查找并执行initInTParent实现,并为您提供最终的输出。

总而言之,无论类层次结构中的哪个方法被调用,如果它是在self上调用的,它将始终执行该方法的派生最多的实现。 希望这有助于,如果您有任何问题,请让我知道!

你的类图如下所示:

类图

initWithName:消息发送给InTSon的实例时,系统将在InTSon的方法表中查找该方法,并find我们调用的方法-[InTSon initWithName:] 。 该方法简化,如下所示:

 // -[InTSon initWithName:] - (id)initWithName:(NSString *)name { return [super initWithName:name]; } 

这个方法确实是[super initWithName:name] 。 因为它将消息发送给super ,所以系统在self的类的超类的方法表中查找。 你的对象的类是InTSon ,它的超类是InTParent 。 所以当-[InTSon initWithName:][super initWithName:name] ,系统在InTParent的方法表中InTParent方法。 它find我们调用的方法-[InTParent initWithName:] 。 该方法简化,如下所示:

 // -[InTParent initWithName:] - (id)initWithName:(NSString *)name { return [self init]; } 

这个方法做[self init] 。 因为它将消息发送给self ,系统会在方法表中查找self的类。 即使我们在-[InTParent initWithName:]self仍然是InTSon类的一个实例 。 所以系统在InTSon的方法表中InTSon init方法。 它find了我们所称的方法-[InTSon init] 。 该方法简化,如下所示:

 // -[InTSon init] - (id)init { return [super initWithName:@"sdas"]; } 

此方法执行[super initWithName:] ,因此系统查找超类的( InTParent 's)方法表并查找-[InTParent initWithName:]方法。 正如我们刚刚看到的, -[InTParent initWithName:]最终调用[InTSon init] 。 所以我们得到无限的recursion和应用程序崩溃。

为了解决这个问题,你需要select一个InTParent的init方法作为它的指定初始化方法。 你应该阅读苹果文档中指定的初始值设定项。

您应该selectinitWithName:方法作为InTParent的指定初始值设定项。 这个方法不能发送任何init消息给self 。 它应该发送超级指定的初始化消息(在NSObject的情况下是init消息),它应该发送给super 。 所以你需要编写-[InTParent initWithName:]方法如下:

 - (id)initWithName:(NSString *)name { // init is NSObject's designated initializer, and we send it to super. if ((self = [super init])) { // your initialization code here } return self; } 

通过select指定的初始值设定项,并使指定的初始值设定项仅super类的指定初始值设定项消息发送给super ,可防止无限recursion。

因为“self”是“InTSon”,所以[self init]调用“InTSon”初始化方法。