构造器

1、指定构造函数(Designated Initializer)

在 OC 的很多头文件中,都会出现NS_DESIGNATED_INITIALIZER这个宏,如:

1
2
- (instancetype)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil NS_DESIGNATED_INITIALIZER;

这个宏就是 “指定构造函数” 的标志,它用来告诉调用者使用这个方法来初始化类对象。一个类可以定义多个构造方法,不同的构造方法可以传入不同的参数,或者通过不同的方式来初始化一个类对象,指定构造函数通常是参数最多的构造函数。一个类必须有一个指定构造器,但并不是说只能有一个。如果必要,你可以声明多个,但是通常情况下一个就足够了。

有时候为了方便,我们想使用尽量少或者不用参数,就能创建一个类对象。这时就可以使用“便利构造函数”来解决。

2、便利构造函数(Convenience Initializer)

这是为了方便调用者快速创建一个类对象而定义的一种构造函数。通常会在便利构造函数中给成员变量提供一个默认值。

#示例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#import <Foundation/Foundation.h>

@interface Initializer : NSObject
{
NSString *aTitle;
NSDate *aDate;
}

//Designated Initializer
- (instancetype)initWithTitle:(NSString *)title
date:(NSDate*)date NS_DESIGNATED_INITIALIZER;

//Convenience Initializer
- (instancetype)initWithTitle:(NSString *)title;

//不希望调用父类(NSObject)的这个 Designated Initializer
- (instancetype)init NS_UNAVAILABLE;
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "Initializer.h"

@implementation Initializer

//父类(NSObject)的 Designated Initializer
- (instancetype) init
{
return [self initWithTitle:@"defaultTitle"];
}

//Convenience Initializer
- (instancetype)initWithTitle:(NSString *)title
{
return [self initWithTitle:title date:[NSDate date]];
}

//Designated Initializer
- (instancetype) initWithTitle:(NSString *)title
date:(NSDate*)date
{
if (self = [super init]) //调用父类的指定构造器
{
aTitle = title;
aDate = date;
}
return self;
}

调用示例:

1
2
3
4
5
6
7
//1
Initializer *ai1 = [[Initializer alloc] init];
//2
Initializer *ai2 = [[Initializer alloc] initWithTitle:@"title2"];
//3
Initializer *ai3 = [[Initializer alloc] initWithTitle:@"title3"
date:[NSDate date]];

上面的调用示例中,第一种在编译时会报错。因为不希望调用者使用此方法来初始化这个类对象,所以头文件中已把init方法声明为NS_UNAVAILABLE

3、使用规范

如果子类有Designated Initializer,那么这个Designated Initializer 中必须调用它直接父类的Designated Initializer,并且需要重写父类的Designated Initializer

如果子类有Designated Initializer,那么Convenience Initializer必须调用这个子类中其它初始化函数(包括Designated Initializer和其他Convenience Initializer),不能调用 super 的初始化函数。

由上可以推理出:

  • Convenience Initializer 只能调用自己类中的其他初始化方法。
  • Designated Initializer 才有资格调用父类的 Designated Initializer。
  • 所有的 Convenience Initializer 最终都会调到该类的 Designated Initializer。

构造器
https://davidlii.cn/2017/12/24/initializer.html
作者
Davidli
发布于
2017年12月24日
许可协议