我无法理解 Stephen Kochan 的“Objective-C 编程”一书中的以下内容 - 第 4 版。我希望你能帮助我理解它。
在第 10 章“初始化对象”一节中,Stephen 写道:
在编写初始化程序时,您应该遵循以下两种策略。
每当您的类中的一个对象被初始化时,您可能想要做一些特别的事情。例如,这是创建类使用和通过一个或多个实例变量引用的对象的理想场所。一个完美的例子就是我们的 Rectangle 类;在 init 方法中分配矩形的 XYPoint 原点是合理的。为此,我们只需要重写继承的 init 方法。
有一个用于覆盖 init 的标准“模板”,它看起来像这样:
- (id) init
{
self = [super init];
if (self) {
// initialisation code here.
}
return self;
}
此方法首先调用父初始化程序。执行父级的初始化程序可确保正确初始化任何继承的实例变量。
您必须将执行父级的 init 方法的结果分配回自身,因为初始化程序有权更改对象在内存中的位置(意味着其引用将更改)。
如果父级的初始化程序成功,则返回的值将非零,正如 if 语句所测试的那样。正如注释所示,在后面的块内,您可以为您的对象放置您自己的自定义代码。这通常涉及分配和初始化类中的实例变量。
好的,到目前为止,我已经理解了 Stephen Kochan 想要说的内容,但我完全被下一部分迷惑了。我希望你能帮忙。
如果您的类包含多个初始化程序,则其中一个应该是您指定的初始化程序,并且所有其他初始化方法都应该使用它。通常,这是您最复杂的初始化方法(通常是采用最多参数的方法)。
所以,我的第一个问题是:如果所有其他初始化方法在这种情况下都将使用一个特定的初始化方法,那么为什么还要使用“指定”初始化方法?
Stephen Kochan 继续说:
创建指定的初始化程序将您的主要初始化代码集中在一个方法中。任何继承您的类的人都可以覆盖您指定的初始化程序,以确保正确初始化新实例。
你能举个例子吗?我不太确定我明白他在说什么。
斯蒂芬继续说:
基于该讨论,您的 Fraction 类的初始化方法 initWith:over: 可能如下所示:
- (Fraction *) initWith:(int)n over:(int)d
{
self = [super init];
if (self) {
[self setTo: n over: d];
}
return self;
}
在 super 的初始化(以及它的成功,如返回一个非零值所示)之后,您使用该
setTo:over:
方法来设置您的 Fraction 的分子和分母。与其他初始化方法一样,您应该返回已初始化的对象,您在此处执行此操作。程序 10.1 测试您的新
initWith:over:
初始化方法。
#import "Fraction.h"
int main (int argc, char *argv[])
{
@autoreleasepool {
Fraction *a, *b;
a = [[Fraction alloc] initWith: 1 over: 3];
b = [[Fraction alloc] initWith: 3 over: 7];
[a print];
[b print];
}
return 0;
}
输出:
1/3
3/7
到目前为止,我已经理解了代码。以下部分我完全不明白:
要遵守前面关于指定初始化程序的规则,您还应该在 Fraction 类中修改 init。如果您的类可能是子类,这一点尤其重要。
下面是 init 方法的样子:
- (id)init
{
return [self initWith:0 over:0];
}
如果我们想要子类化,为什么这很重要?
Stephen Kochan 继续说道:
当您的程序开始执行时,它会将初始化调用方法发送到您的所有类。如果您有一个类和关联的子类,则父类首先获取消息。该消息只向每个类发送一次,并且保证在任何其他消息发送到该类之前发送。目的是让您在此时执行任何类初始化。例如,您可能想在那时初始化一些与该类关联的静态变量。
我也没有真正理解最后一部分。我希望你能提供帮助。