Creating objects 创建对象

在 Objective-C 和 Swift 里面创建对象,是天差地别的两件事情。

  1. 在 Objective-C 里面你不需要给属性设定默认值, Objective-C 会自动把对象设定为 nil,数字设定为 0。
  2. 在你初始化自己的属性之前,你必须要调用父类的 init 方法。
  3. 在你初始化完你的你自己的属性之前,你可以在你的初始化器里调用其他的方法。
  4. 所有的初始化器都默认是失败的,「失败」指的是它们会返回 nil,在继续之前下一次的操作之前,你必须要先去确认初始化是否成功。
  5. 你需要用 self 来返回。

上面的这五点里,第二点和第三点是基于第一点成立的。因为 Objective-C 会自动的给所有属性赋值,所以在初始化完成之前 你调用别的方法,包括了父类的 init。

这就是我提到过的,直接访问实例变量的第二种情景——创建对象。

之前我们讲了第一种情况,就是自定义 getter 和 setter 访问器。

在创建对象的时候,使用实例对象的原因是,由于键值观察(KVO)的存在,当你访问属性的时候,有可能访问到别的东西,过多的数据访问就会导致程序崩溃。

我们来看一个例子,在这个例子里,我们给 Person 类创建了 name 和 age 属性,而在另外一个 Office 类里,我们访问 Office 对象,观察每一个员工的 age 属性,那么当员工生日的时候,就可送上蛋糕。

如果我们在初始化的时候,age 设置在了前面,那 Office 对象想读取 name 属性的时候,就会都找不到这个属性。

self.age = 26;
// who knows what code happens here?
self.name = @“Taylor Swift”;

如果我们自定义 setAge 方法来获取 name 属性也一样糟心,就算在 self.name 后面用 self.age 也是一样的。

一个吐槽,在日常的工作里,我们会发现有很多人,在不应该直接使用实例变量的时候呢,真的很开心。但是当应该要用实例变量的时候,反而不去用了。

在自定义 getter 和 setter 访问器时,我们被要求一定要用实例变量,防止循环引用。但是在创建对象的时候,这只是一个建议,如果说你觉得你的实现逻辑很棒的话,当然也可以不用。

那如何定义实现逻辑棒不棒嘞?其实是很简单的,你可以在初始化的时候,先调用 super,的时候,再进行初始化操作。我们可以看一下下面的例子:

- (instancetype)initWithName:(NSString*)name {
    if (self = [super init]) {
        self.name = name;
    }
    return self;
}

把上面这段代码放到 Person.m 文件里面,然后确保你在 Person.h 文件里面修改了接口的写法,在 main.m 文件里就可以这样写:

Person *person = [[Person alloc] initWithName:@"James"];
[person printGreeting];

Objective-C 的初始化器乍一看有点怪怪的。首先要调用 [super init] 方法,然后把这个结果返回给 self ,最后把所有东西放到一个 if 的条件语句里。哪怕这么多年过去了,看这个还是很不爽(…… 它的意思是「试着去创建一个父类的实例,如果创建成功了,就初始化自己的属性」。如果 [super init] 失败了,self = nil 就会返回一个 false,接下来的代码就不会执行了。

如果你有一个继承链,用 [super init] 可能会调用到另一个父类那里去……所以每一个子类都会在初始化的时候加一点自己的信息进去,防止乱调用……(´・_・`)

results matching ""

    No results matching ""