前言
一开始学习objective—C,我对于对象的初始化知之甚少,存在一定的概念混淆,在这里做个梳理和记录,希望对同样困扰的人有所帮助。
初始化方法
初始化方法用于初始化当前对象、实例变量。
苹果文档给出的对象生成图:
每个初始化方法的方法名都以英文单词init开头,会带参数,同其他的实例方法无异。在Objective-C中的命名规范无需重复,必须严格遵守,忽视命名约定会产生超过预期的错误。
实现初始化方法的基本步骤如下:
- 调用父类初始化方法,即父类的指定初始化方法,并检查其返回值。(使用保留字super指定超类。)若返回值不为nil,则可以继续初始化。
- 对象的实例变量赋值。
返回初始化对象,或者如果初始化不成功,则返回nil。
举个例子1,指定初始化方法:
- (id)init {
//1.调用父类初始化方法,也是指定初始化方法
self = [super init];
if (self ) {
//2.实例变量赋值
_date = [[NSDate date] retain];
}
//3.返回初始化对象
return self;
}
指定初始化方法
指定初始化方法的作用是确保对象的每个实例变量都处在一个有效(valid)的状态,即初始化后的对象发送信息时,输出的结果是可预期的。
同一个类会因不同的需求,会提供一个以上的初始化方法,但无论其有多少个初始化方法,必须有一个指定初始化方法(designated initializer)。
指定初始化方法的参数通常和最重要、最常用的实例变量相对应,确保继承的程序能够正确地初始化所有实例变量。
初始化方法的几个规则
- 1.子类会继承父类所有的初始化方法,也可以为类新加入任意数量的初始化方法
- 2.每个类都要选定一个指定初始化方法,其余为便利初始化方法
- 3.在执行其他便利初始化工作之前,必须先用指定初始化方法调用父类的指定初始化方法([super init…])(直接或间接),只有指定初始化函数才有资格调用父类的指定初始化方法
- 4.便利初始化方法要调用指定初始化方法([self init…])(直接或间接),而且便利初始化函数只能调用自己类中的其他初始化方法
- 5.如果某个类所声明的指定初始化方法与其父类的不同,就必须覆盖父类的指定初始化方法并调用新的指定初始化方法(直接或间接)
6.如果某个类提供了一个或者多个指定初始化方法,就必须实现其父类的所有的指定初始化方法
如果违背上面任意一条规则,编译时就会报警告。苹果官方关于初始化规则的图较为形象描述:
举个例子1.TestClass
@interface TestClass
NSString *_itemName;
NSString *_serialNumber;
int _valueInDollars;
NSDate *_dateCreated;
@end
@implementation TestClass
- (instancetype)initWithItemName:(NSString *)name
valueInDollars:(int)value
serialNumber:(NSString *)sNumber
{
// 指定初始化方法,必须先调用父类的指定初始化方法
// 调用父类初始化方法
self = [super init];
// 初始化是否成功?
if (self) {
// 实例变量初始化赋值
_itemName = name;
_serialNumber = sNumber;
_valueInDollars = value;
_dateCreated = [[NSDate alloc] init];
}
// 返回初始化对象
return self;
}
- (instancetype)initWithItemName:(NSString *)name
{
//便利初始化方法
//便利初始化函数只能调用自己类中的其他初始化方法
return [self initWithItemName:name
valueInDollars:0
serialNumber:@""];
}
- (instancetype)init
{
//便利初始化方法
//便利初始化函数只能调用自己类中的其他初始化方法
return [self initWithItemName:@"Item"];
}
@end
规则总结就两条:
- 便利初始化方法实现只能而且必须调用自己类中的其他初始化方法
- 指定初始化方法实现才有资格而且必须调用父类的指定初始化方法
例子1 中,执行newObject = [TestClass alloc]int],初始化调用的过程应该为:TestClass:init -> TestClass:initWithItemName -> TestClass:initWithItemName:valueIndollars:serialNumber -> superClass:init;
例子1初始化调用过程:而初始化方法的实际执行顺序恰好相反,这个逻辑很重要。
对象的创建过程是从根类到子类依次初始化所有成员变量。苹果文档给出关于多个初始化方法的对象初始化过程:
若有不足,请大家多多指正。