我为什么要调用self =
比方说,我创build我的类和它的init
方法。 我为什么要调用并返回分配给自己的超类init
值? 它涵盖了哪些情况?
我将不胜感激为什么我会需要它的cocoa超类和非cocoa。
你的意思是为什么
self = [super init];
而不是
[super init];
两个原因:
- 在初始化中,失败表示为返回零。 您需要知道超级对象的初始化是否失败。
- 超类可能会select用另一个对象replace+ alloc所返回的自我。 这很less见,但在class级集群中经常发生。
回应Michael的评论编辑:
我可以理解为什么我需要保存并返回[超级初始化]。 但是这只是惯例和好看让我们用自己作为一个临时variables来传递结果吗?
编号实例variables是相对于自指针访问的,所以在下面:
-(id) init { self = [super init]; if (self != nil) { myBoolIvar = YES; // The above is an implicit version of self->myBoolIvar = YES; } return self; }
自己显然已经指向了正确的内存块,即你将要返回的内存块。
另一点是,如果超级初始化返回不同的类实例,那么在该行之后的其余代码可能甚至没有意义,导致内存泄漏和崩溃,甚至没有谈论从该类实例化的对象。
这可能是一个问题。 如果我将子类NSNumber和[超级初始化]决定返回一个NSString(它可以 – 没有什么可以阻止它),这显然是一场灾难。 无论从-init提供的超级返回与子类是否“兼容”,都是为ivars提供空间并进一步子类化或者是一个可怕的bug(当然,除非有问题logging)。 所以,一般来说,你不必担心检查课堂。 但是,请阅读文档。 请参阅NSString文档中有关子类NSString的部分。
我知道我的答案有点迟,但是我无法阻止自己发布一个链接,我发现这个链接对于清除我对这个问题的怀疑非常有用。
Matt Gallagher:当你指定[super init]给自己时,这意味着什么?
编辑:根据评论,这里是链接中的要点
理解为什么self=[super init];
我们需要考虑很多方面。 我们一个一个去解决。
什么是self
每个方法都有两个隐藏的参数: self
和_cmd
。 所以方法调用
- (id)initWithString:(NSString *)aString
被编译器改变成这样的函数调用
id initWithString(id self, SEL _cmd, NSString *aString);
为什么我们需要自我?
现实情况是,编译器使用self
参数来parsing对方法内的实例variables的引用。
假设我们有一个setValueToZero
方法, value
是它所属类的实例variables,那么实现
- (void)setValueToZero { value = 0; }
会被编译器转换成这样的函数
void setValueToZero(id self, SEL _cmd) { self->value = 0; }
当init
被调用时, self
已经有了一个值吗?
以下是一个典型的对象创build和初始化的例子。
[[MyClass alloc] initWithString:@"someString"]
在这里,当我们进入initWithString
方法的时候,self会将新分配的对象作为它的值(也就是来自[MyClass alloc]
的返回值)。 事实上,它几乎保证是正确的,最终的价值。
为什么self = [super init];
?
这是因为[super init]
被允许做三件事之一:
- 返回自己的接收器(
self
指针不变),并初始化了inheritance的实例值。 - 用初始化的inheritance实例值返回一个不同的对象。
- 返回
nil
,表示失败。
在第一种情况下,作业对self
没有影响。 在第三种情况下,初始化失败, self
被设置nil
,并返回。
第二种情况是指派给self
的原因。 考虑以下几点
- (id)initWithString:(NSString *)aString { self = [super init]; if (self) { instanceString = [aString retain]; } return self; }
我们希望从中转换
instanceString = [aString retain];
至
self->instanceString = [aString retain];
以正确的价值行事,因此我们必须改变self
的价值。
何时会[super init]
返回一个不同的对象?
在以下情况之一
- Singleton对象(总是返回单例,而不是任何后续的分配)
- 其他唯一的对象(
[NSNumber numberWithInteger:0]
总是返回全局的“零”对象) - 当您初始化超类的实例时,类簇会替代私有子类。
- select根据传递给初始值设定项的参数重新分配相同(或兼容)类的类。
除最后一种情况外,如果它们发生变化,则继续初始化返回的对象是一个错误 – 返回的对象已经完全初始化,并且不再需要与您的类相关联。 所以更好的init方法如下
- (id)initWithString:(NSString *)aString { id result = [super init]; if (self == result) { instanceString = [aString retain]; } return result; }
结论
您不需要将[super init]
指派给self
以使大多数类都可以工作。 在一些模糊的情况下,这实际上是错误的事情。
那为什么我们继续分配self
呢? 这是一个初始化器的传统模板,虽然在某些情况下是错误的,但在其他情况下,写这个方法是正确的。
基本上每个Objective-C类都是一个子类。 它是你指定的一个类或NSObject。
在子类(你正在处理的类)中,你可以调用self = [super init]
这基本上做的是调用超类(我上面提到的)init方法(构造函数),并将其分配给当前类。
这确保了超类的初始化方法被调用。
现在如果(自我)这基本上检查,如果上面的一段代码工作。
这样做是为了确保如果你调用超类的实例variables,你就可以这样做。
在大多数情况下,将自己设置为[super init]将不会执行任何操作,因为[super init]会自动返回自身。 但是有一些罕见的情况,super init会返回不同的东西。 如果由于某种原因未能初始化超类,它可能返回nil,或者可能决定返回一个完全不同的对象。
资源
实现指定的初始化程序
**
自
**在一个方法中,self是一个隐式的局部variables。 不需要声明它,它自动设置为指向发送消息的对象。 (在Android编程中就是这样的。)通常情况下,使用self来让对象可以发送消息给自己。 示例:
return self;
**
超
**当我们重写一个方法时,我们想要保持超类的方法正在做,并让你的子类添加新的东西。 为了方便起见,在Objective-C中有一个叫做super的编译器指令。 超级怎么样? 通常,当您向对象发送消息时,search该名称的方法将从对象的类中开始。 如果没有这样的方法,search继续在对象的超类中。 search将继续inheritance层次结构,直到find合适的方法。 (如果它到达层次结构的顶部并且没有find方法,则抛出exception)。 当我们向super发送消息的时候,我们正在向自己发送消息,但是search方法会跳过对象的类并从超类开始。 在上面的例子中,我们发送init消息给super。 这将调用NSObject的init方法。
因为你必须以某种方式初始化对象,并且大概你想做任何初始化,所以需要完成一个超类,因为你是从这个超类中下来的。