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方法 - >父初始化方法
请帮助我!
答案 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)
您的班级图如下所示:
当您将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方法。