Why can't a designated initializer call a secondary initializer in its base class?

走远了吗. 提交于 2019-12-08 16:19:40

问题


According to the documentation, a class's designated initializer in Objective-C must call the designated initializer of its base class.

Another rule is that secondary initializers must call the designated initializer of their own class.

But if the second rule is followed, why can't a designated initializer call a secondary initializer in its base class? This base secondary initializer will ultimately call its own level's D.I., so the object will still be properly initialized, right?

The difference seems to be who chooses defaults for missing variables -- you or your base class.


回答1:


Let's consider NSSet. It has a designated initializer:

- (id)initWithObjects:(const id *)objects count:(NSUInteger)cnt {
   // initialization code here
   return self;
}

It also has some secondary initializers, like this one:

- (id)initWithArray:(NSArray *)array {
    NSUInteger count = array.count;
    id objects[count];
    [array getObjects:objects range:NSMakeRange(0, count)];
    return [self initWithObjects:objects count:count];
}

Now you want a subclass of NSSet that automatically rejects the string "Bob". So you dutifully override the designated initializer in your subclass, but you call one of super's secondary initializers:

@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];
}

What happens when you do this:

BobRejectingSet *noBobs = [[BobRejectingSet alloc] initWithArray:someObjects];

Since you didn't override initWithArray:, the program calls -[NSSet initWithArray:], which calls the designated initializer, initWithObjects:count:. You overrode the designated initializer, so it calls your method. Your method filters out the Bobs, and then calls super's secondary initializer, initWithArray:… which turns around and calls your designated initializer override again. Unlimited recursion. Stack overflow. You get the segmentation-violation-core-dumped blues.

That's why you always use super's designated initializer.




回答2:


If a designated initializer were to call a secondary initializer in its own class, then it wouldn't be serving the role of designated initializer. The point of the designated initializer is so a subclass implementer knows the single initializer s/he can override that all other initializers will funnel through.

If a designated initializer in a subclass were to call a non-designated initializer in its superclass, then the superclass initializer would likely turn around and call another of the initializers. Due to the dynamic nature of method dispatch, it can't restrict that to calling only the methods implemented at its level. That call is very likely to be to one of the subclass's overrides, which would funnel into the subclass's designated initializer, resulting in infinite recursion.



来源:https://stackoverflow.com/questions/10057461/why-cant-a-designated-initializer-call-a-secondary-initializer-in-its-base-clas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!