关于父对象的init方法

时间:2012-09-07 02:23:16

标签: ios

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(扩展父级) 像这样:

@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"];

为什么输出是: 子initWithName方法 - >父initWithName方法 - > Son init方法 - >父初始化方法

但在Java中,它可能是这样的: 子initWithName方法 - >父initWithName方法 - >父初始化方法

请帮助我!

3 个答案:

答案 0 :(得分:2)

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

在较高级别,只要在任何对象上调用方法,Objective-C运行时就会查找提供派生最多(类层次结构中最深)类的实现。如果它没有找到它,它将是下一个最大的派生,依此类推,直到NSObject。第一次找到与选择器匹配的实现(大致方法名称)时,它将执行该实现。当您调用super时,您指定将消息发送到下一个派生类的该方法的实现。

因此,在您的代码中,您在alloc类上调用InTSon,该类返回IntSon的实例,并将isa指针设置为类对象{{1 }}。 InTSon指针是在升级类层次结构的过程中查找方法实现的方式。

所以在你有一个isa实例之后,你会在它上面调用InTSon,它会检查initWithName:指向的类(isa为实现它找到它,所以执行它,导致你的第一个输出:

InTSon

紧接着,您调用该方法的超类实现,该实现在"Son initWithName method"中查找其InTParent的实现并执行该代码,从而产生第二个输出:

initWithName:

现在,您可以在此处看到与Java的偏差 - 您在Parent initWithName method上致电init。但是,self是指向self实例的指针。因此,当运行时解析此消息时,它首先查看InTSon类中init的实现。当然,它找到它,并执行该方法的代码,它为您提供第三个输出InTSon。接下来,您调用super,它会查找并执行Son init method InTParent的实现,并为您提供最终输出。

总而言之,无论在类层次结构中 where ,都会调用一个方法,如果在init上调用它,它将始终执行最多该方法的派生实现。希望这会有所帮助,如果您有任何疑问,请告诉我们!

答案 1 :(得分:1)

您的班级图如下所示:

class diagram

当您将initWithName:消息发送到InTSon的实例时,系统会在InTSon的方法表中查找该方法,并找到我们调用的方法{{1 }}。简化的方法如下所示:

-[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 initWithName:]

此方法执行// -[InTParent initWithName:] - (id)initWithName:(NSString *)name { return [self init]; } 。因为它将消息发送到[self init],系统会在方法表中查找self的类。即使我们在self -[InTParent initWithName:]仍然是self的实例。因此,系统会在InTSon的方法表中查找init方法。它找到了我们称之为InTSon的方法。简化的方法如下所示:

-[InTSon init]

此方法执行// -[InTSon init] - (id)init { return [super initWithName:@"sdas"]; } ,因此系统查找超类的([super initWithName:])方法表并找到InTParent方法。正如我们刚刚看到的那样,-[InTParent initWithName:]最终会调用-[InTParent initWithName:]。所以我们得到无限递归,应用程序崩溃。

要解决此问题,您需要选择一个[InTSon init]的init方法作为指定的初始化程序You should read about designated initializers in Apple's documentation.

您应该选择InTParent方法作为initWithName:指定的初始化程序。此方法必须InTParent发送任何初始化消息。它应该发送超级指定的初始化消息(在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; } ,可以防止无限递归。

答案 2 :(得分:0)

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