标签:
一个类,可能有很多初始化函数,但是有主次之分,最主要的初始函数应该对类内应当需要初始化的变量进行初始化。这个最主要的初始函数即Designated Initializer(指定初始化器),可以理解为是类的默认初始函数。比如,UIView的Designated Initializer是initWithFrame:而不是init:
NSObject的Designated Initializer为init;
UIView的Designated Initializer为initWithFrame:;
TestView继承于UIView,它有一个属性Name,所以它的Designated Initializer为initWithFrame:andName:
假如不遵循第2点,initWithFrame:andName:的实现如下
- (id)initWithFrame:(CGRect)frame andName:(NSString *)name { if (self = [super init]) { self.name = name; } return self; }
测试1:使用子类的Designated Initializer初始化子类对象
TestView *testView = [[TestView alloc] initWithFrame:CGRectZero andName:@""];
调用顺序如下:
1)TestView的initWithFrame:andName:
2)UIView的init
3)UIView的initWithFrame
4)NSObject的init
此时没问题,3个类的Designated Initializer都被调用了
测试2:使用父类的Designated Initializer初始化子类对象
TestView *testView = [[TestView alloc] initWithFrame:CGRectZero];
调用顺序如下:
1)UIView的initWithFrame
2)NSObject的init
此时有问题,TestView的Designated Initializer没有被调用
而测试1之所以没问题,是因为UIView遵循了原则1和原则2。
好,现在我们将TestView修改为遵循原则1和原则2。
- (id)initWithFrame:(CGRect)frame andName:(NSString *)name { if (self = [super initWithFrame:frame]) { self.name = name; } return self; } - (id)initWithFrame:(CGRect)frame { return [self initWithFrame:frame andName:@""]; }
测试1:使用子类的Designated Initializer初始化子类对象
TestView *testView = [[TestView alloc] initWithFrame:CGRectZero andName:@""];
调用顺序如下:
1)TestView的initWithFrame:andName:
2)UIView的initWithFrame
3)NSObject的init
此时没问题,3个类的Designated Initializer都被调用了
测试2:使用父类的Designated Initializer初始化子类对象
TestView *testView = [[TestView alloc] initWithFrame:CGRectZero];
调用顺序如下:
1)TestView的initWithFrame
2)TestView的initWithFrame:andName:
3)UIView的initWithFrame
4)NSObject的init
此时没问题,3个类的Designated Initializer都被调用了
- (id)initWithFrame:(CGRect)frame { if (self = [super initWithFrame:frame]) { self.name = name; //注意这里的name不是通过初始化函数传递进来的 } return self; }
//Super Override - (id)initWithFrame:(CGRect)frame { return [self initWithFrame:frame andName:@""]; } //Designated Initializer - (id)initWithFrame:(CGRect)frame andName:(NSString *)name { if (self = [super initWithFrame:frame]) { self.name=name; } return self; } //Instance Secondary Initializer - (id)initWithName:(NSString *)name { return [self initWithFrame:CGRectZero andName:name]; } //Instance Secondary Initializer - (id)initWithName2:(NSString *)name { return [self initWithName:name]; } //Class secondary initializer + (id)testViewWithName:(NSString *)name { TestView *testView=[[TestView alloc] initWithFrame:CGRectZero andName:name]; return testView; }
可以看到方法initWithName2调用的顺序是initWithName2–>initWithName–>initWithFrame:andName:,最后指向了Designated Initializer。
同时需要注意的是,Secondary initializers不仅可以是实例方法,也可以是静态方法,如testViewWithName:
还有一个问题是为什么Secondary Initializer内不能直接调用父类的初始化器?
我们要明确,调用父类的Designated Initializer的那个方法就是子类的Designated Initializer,Designated Initializer有且只有1个,所以即使有多个初始化函数,也要保证只能有一个是Designated Initializer
参考链接
《正确编写Designated Initializer的几个原则》
标签:
原文地址:http://www.cnblogs.com/chenyg32/p/4870303.html