【问题标题】:Why can't a designated initializer call a secondary initializer in its base class?为什么指定的初始化程序不能在其基类中调用辅助初始化程序?
【发布时间】:2012-04-07 19:07:42
【问题描述】:

根据文档,Objective-C 中类的指定初始化程序必须调用其基类的指定初始化程序。

另一个规则是辅助初始化器必须调用它们自己类的指定初始化器。

但是如果遵循第二条规则,为什么指定初始化器不能在其基类中调用辅助初始化器?这个基础二级初始化器最终会调用它自己关卡的 D.I.,所以对象仍然会被正确初始化,对吧?

区别似乎在于谁为缺失的变量选择默认值——你还是你的基类。

【问题讨论】:

标签: objective-c inheritance coding-style designated-initializer


【解决方案1】:

让我们考虑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”。因此,您尽职尽责地覆盖了子类中指定的初始化程序,但您调用了 super 的辅助初始化程序之一:

@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,然后调用 super 的辅助初始化程序 initWithArray:... 它转身再次调用您指定的初始化程序覆盖。无限递归。堆栈溢出。你会得到分段违反核心转储的忧郁。

这就是为什么你总是使用 super 的指定初始化器。

【讨论】:

  • 大概只有当你的 init 被称为与超类的 init 之一相同的东西时才会发生这种情况。如果你叫它initWithoutBob: 你会没事的吧?
  • 那么它就不是指定的初始化器了。
【解决方案2】:

如果指定初始化器在其自己的类中调用辅助初始化器,则它不会充当指定初始化器的角色。指定初始化器的意义在于,子类实现者知道他/她可以覆盖所有其他初始化器将通过的单个初始化器。

如果子类中的指定初始化程序要调用其超类中的非指定初始化程序,则超类初始化程序可能会转而调用另一个初始化程序。由于方法分派的动态特性,它不能将其限制为仅调用在其级别实现的方法。该调用很可能是对子类的重写之一,这将汇集到子类的指定初始化程序中,从而导致无限递归。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多