根据该文件,在Objective-C类的指定初始化必须调用基类的指定初始化。
另一条规则是,二次初始化必须调用自己的类的指定初始化。
但是,如果第二条规则是其次的,为什么不能在指定初始化调用基类的辅助初始化? 该基地二次初始化最终调用自己的水平的DI,所以对象仍然会被正确的初始化,对不对?
所不同的似乎是谁选择默认值遗漏变量 - 你或你的基类。
根据该文件,在Objective-C类的指定初始化必须调用基类的指定初始化。
另一条规则是,二次初始化必须调用自己的类的指定初始化。
但是,如果第二条规则是其次的,为什么不能在指定初始化调用基类的辅助初始化? 该基地二次初始化最终调用自己的水平的DI,所以对象仍然会被正确的初始化,对不对?
所不同的似乎是谁选择默认值遗漏变量 - 你或你的基类。
让我们考虑NSSet
。 它有一个指定初始化:
- (id)initWithObjects:(const id *)objects count:(NSUInteger)cnt {
// initialization code here
return self;
}
它也有一定的辅助初始化,像这样的:
- (id)initWithArray:(NSArray *)array {
NSUInteger count = array.count;
id objects[count];
[array getObjects:objects range:NSMakeRange(0, count)];
return [self initWithObjects:objects count:count];
}
现在,你想的一个子类NSSet
自动拒绝字符串“鲍勃”。 所以,你尽职尽责地重写指定初始化你的子类,但你叫超的二次初始化之一:
@implementation BobRejectingSet
- (id)initWithObjects:(const id *)objects count:(NSUInteger)count {
NSMutableArray *array = [[NSMutableArray alloc] initWithCount:count];
for (NSUInteger i = 0; i < count; ++i) {
if (![objects[i] isEqual:@"Bob"]) {
[array addObject:objects[i]];
}
}
return [super initWithArray:array];
}
当你这样做会发生什么:
BobRejectingSet *noBobs = [[BobRejectingSet alloc] initWithArray:someObjects];
既然你没有重载initWithArray:
程序调用-[NSSet initWithArray:]
,它调用指定初始化, initWithObjects:count:
。 你推翻了指定初始化,所以它调用你的方法。 你的方法过滤掉鲍勃,然后调用超类的二次初始化, initWithArray:
...这转了一圈,并再次调用您指定的初始化覆盖。 无限递归。 堆栈溢出。 你得到的分割违章-核心转储布鲁斯。
这就是为什么你总是使用超类的指定初始化。
如果指定的初始化是调用二次初始化在自己的类,那么就无法放送指定的初始化的作用。 指定初始化的要点是这样一个子类实现者知道单初始化他/她可以覆盖所有其他初始化时将漏斗通过。
如果在子类中的指定初始化是调用一个非指定初始化其超类中,则超初始化可能会掉头,并调用另一个初始化的。 由于方法调度的动态性质,它不能限制只在调用它的级别实现的方法。 这一呼吁是非常有可能是子类的优先选项之一,这将漏斗到子类的指定初始化,导致无限递归。