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

76 Views Asked by At

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?

1

There are 1 best solutions below

6
On BEST ANSWER

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).