iosobjective-cclass-cluster

Why my code did not get into [super init] function?


There are three class Question,Choiceand Blank,and Question is the super class of Choice and Blank.

Then, I write some methods as follows:

- (instancetype)initWithQuestionType:(NSString *)questionType
{
    NSLog(@"**class:%@",[self class]);
    if([self isMemberOfClass:[Question class]])
    {
        self = nil;
        if([questionType isEqualToString:@"choice"])
        {
            NSLog(@"--class:%@",[self class]);
            self = [[Choice alloc] initWithQuestionType:questionType];
            NSLog(@"++class:%@",[self class]);
        }
        else
        {
            self = [[Blank alloc] initWithQuestionType:questionType];
        }

        return self;
    }

    return [super init];
}

- (instancetype)init
{
    NSLog(@"Init!");

    return [self initWithQuestionType:@"unKnow"];
}

and then:

Question *question = [[Question alloc] initWithQuestionType:@"choice"];

the output is:

2015-10-16 20:58:50.278 initSample[3687:161396] **class:Question
2015-10-16 20:58:50.279 initSample[3687:161396] --class:(null)
2015-10-16 20:58:50.279 initSample[3687:161396] **class:Choice
2015-10-16 20:58:50.280 initSample[3687:161396] ++class:Choice

and I can't understand why [super init] did not be executed?


Solution

  • Your [super init] method is being called:

    1. [Question initWithQuestionType] is called.
    2. The first if is true, so it's entered.
    3. The question type is "choice" so [Choice initWithQuestionType:] is called.
    4. As Choice does not override -initWithQuestionType:, this will call [Question initWithQuestionType:] again.
    5. This time the if is false, so it's not entered, and [super init] is being called.

    This is being shown in your log messages (add an another log call before the [super init] method, to prove this).

    However it's a very confusing and difficult to maintain factory method, and it's much easier to use a class factory method, as below. That way your init methods will be much more straight-forward and easier to maintain.

    + (Question *)questionWithType:(NSString *)type
    {
        if ([type isEqualToString:@"choice"])
            return [[Choice alloc] init];
        else
            return [[Blank alloc] init];
    }
    

    Also consider using an enum to represent the type, rather than a string (quicker/more efficient).