假设我创建了我的类及其init
方法。为什么我应该调用并返回分配给self的超类init
的值?它涉及哪些案例?
我很感激为什么我需要Cocoa超类和非Cocoa的例子。
答案 0 :(得分:44)
你的意思是
self = [super init];
而不是
[super init];
有两个原因:
编辑回应迈克尔的评论:
我能理解为什么我需要保存并返回[super init]。但这只是惯例而且好看使我们使用self作为临时变量来传递结果吗?
没有。相对于自指针访问实例变量,因此在下面:
-(id) init
{
self = [super init];
if (self != nil)
{
myBoolIvar = YES;
// The above is an implicit version of self->myBoolIvar = YES;
}
return self;
}
自我显然必须指向正确的记忆块,即你将要返回的记忆块。
另一点是,如果超级init返回不同的类实例,那么该行之后的其余代码甚至可能没有意义,导致内存泄漏和崩溃,甚至没有谈论从该类实例化的对象。
这可能是个问题。如果我继承了NSNumber并且[super init]决定返回一个NSString(它可以 - 没有什么可以阻止它)那显然是一场灾难。无论来自-init的超级回报必须与子类“兼容”,从而为ivars提供空间并进一步细分,或者这是一个可怕的错误(当然,除非记录问题)。所以,一般来说,你不必担心检查课程。但是,请阅读文档。例如,请参阅NSString文档中有关子类化NSString的部分。
答案 1 :(得分:26)
我知道我的回答有点晚了,但我不能阻止自己发布一个链接,我发现这个链接对于清除我对此问题的疑虑非常有用。
Matt Gallagher: What does it mean when you assign [super init] to self?
编辑:根据评论,以下是链接中的要点
要理解为什么self=[super init];
我们需要考虑很多要点。让我们一个一个地解决它。
什么是self
每种方法都有两个隐藏参数:self
和_cmd
。所以方法调用
- (id)initWithString:(NSString *)aString
编译器将更改为像这样的函数调用
id initWithString(id self, SEL _cmd, NSString *aString);
为什么我们需要自我?
实际情况是编译器使用self
参数来解析对方法内部的实例变量的任何引用。
假设我们有一个方法setValueToZero
而value
是它所属的类的实例变量,那么实现
- (void)setValueToZero
{
value = 0;
}
将由编译器转换为类似
的函数void setValueToZero(id self, SEL _cmd)
{
self->value = 0;
}
调用self
时init
是否已有值?
以下是典型对象创建和初始化的示例。
[[MyClass alloc] initWithString:@"someString"]
在这里,当我们进入initWithString
方法时,self将新分配的对象作为其值(即,[MyClass alloc]
的返回值)。事实上,它几乎保证是正确的最终价值。
为什么self = [super init];
?
这是因为[super init]
被允许做以下三件事之一:
self
指针不会更改),并继承初始化的实例值。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]
何时会返回其他对象?
在以下某种情况下
[NSNumber numberWithInteger:0]
始终返回全局“零”对象)除了最后一种情况之外,如果返回的对象发生更改则继续初始化是错误的 - 返回的对象已经完全初始化,并且不再需要与您的类相关。所以更好的init方法如下
- (id)initWithString:(NSString *)aString
{
id result = [super init];
if (self == result)
{
instanceString = [aString retain];
}
return result;
}
<强>结论强>
您无需将[super init]
分配给self
即可使大多数课程都有效。在一些不起眼的案例中,这实际上是错误的。
那么为什么我们继续分配给self
?它是初始化程序的传统模板,虽然在某些情况下它是错误的,但在其他情况下,这是正确的,这是为了期望这种方法。
答案 2 :(得分:4)
基本上每个Objective-C类都是一个子类。它是你指定的某个类或NSObject。
在子类(您正在处理的班级)中,您致电 self = [super init]
这基本上做的是调用超类(我上面提到的那些)init方法(构造函数)并将其分配给当前类。
这确保了超级班级&#39;初始化方法被称为。
现在 如果(个体经营) 这基本上检查上面的代码是否有效。
这样做是为了确保如果你调用超类的某个实例变量,你就能够这样做。
答案 3 :(得分:1)
在大多数情况下,将self设置为[super init]不会发生任何事情,因为[super init]无论如何最终会返回自我。然而,有一些罕见的情况,[super init]将返回不同的东西。如果由于某种原因无法初始化超类,它可能返回nil,或者它可能决定返回一个完全不同的对象。
答案 4 :(得分:1)
Implementing The Designated Initializer
**
** 在方法内部,self是一个隐式局部变量。不需要声明它,它会自动设置为指向发送消息的对象。 (在Android编程中类似于此。)通常,使用self来表示对象可以向自己发送消息。示例:
return self;
**
** 当我们重写一个方法时,我们想要保留超类的哪个方法正在做,并让你的子类在其上添加一些新东西。为了简化,Objective-C中有一个名为super的编译器指令。 超级工作如何?通常当您向对象发送消息时,在对象的类中开始搜索该名称的方法。如果没有这样的方法,则搜索在对象的超类中继续。搜索将继续继承继承层次结构,直到找到合适的方法。 (如果它到达层次结构的顶部并且未找到任何方法,则抛出异常)。 当我们向super发送消息时,我们正在向self发送消息,但搜索该方法会跳过该对象的类并从超类开始。在上面的例子中,我们将init消息发送给super。这会调用NSObject的init方法。
答案 5 :(得分:0)
因为你必须以某种方式初始化对象,并且可能你想要进行任何初始化,所以需要完成超类,因为你是从它下降的。