根据文档,在Objective-C中,一个类的指定初始化方法必须调用其基类的指定初始化方法。另一个规则是,辅助初始化方法必须调用其自身类的指定初始化方法。但如果遵循第二个规则,为什么指定初始化方法不能调用其基类中的辅助初始化方法呢?这个基类的辅助初始化方法最终会调用其自己级别的指定初始化方法,所以对象仍将被正确初始化,对吗?区别似乎在于谁为缺失的变量选择默认值——您还是您的基类。
让我们考虑一下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
,该子类会自动拒绝字符串“Bob”。因此,您忠实地重写了您的子类中指定的初始化方法,但是您调用了父类的一种次要初始化方法:
@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:
。您覆盖了指定的初始化器,因此它将调用您的方法。您的方法过滤了Bobs,然后调用超类的辅助初始化器initWithArray:
,...然后反过来又调用了您的指定初始化器覆盖。无限递归。堆栈溢出。您得到了段错误核心转储蓝屏。
这就是为什么您总是要使用超类的指定初始化器。