Overwriting and custom inits in objective-c

150 views Asked by At

I have a class that inherits the MPMoviePlayerViewController. I'm trying to rewrite the init method so that I don't have to repeat code for every other -initWithSomething function. For a custom initWithSomething method this will work. But I can't figure how to make it work for inherited iniWithSomething methods

-(instancetype)init
{
    if(self = [super init]){
        // This is code I don't want to repeat in initWithSomething methods
        [self startWithHiddenControls];

        AVAudioSession *audioSession = [AVAudioSession sharedInstance];
        [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
        [audioSession setActive:YES error:nil];

        [[NSNotificationCenter defaultCenter] removeObserver:self
                                                        name:UIApplicationDidEnterBackgroundNotification
                                                      object:nil];

        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(UIApplicationDidBecomeActive)
                                                     name:UIApplicationDidBecomeActiveNotification
                                                   object:nil];
    }
    return self;
}

-(instancetype)initWithContentURL:(NSURL *)contentURL
{

    // Not overwriting doesn't use my overwriten init so i must do it.
    // But how ?!?
    // why [super init] makes inifinite loop? (I know the norm is [super <same method>])
    if(self = [self init]){} // this will not work. Inifinite loop I believe.

    return self;
}

//This method works fine
- (instancetype)initWithSettings:(NSDictionary *)settings
{
    // [self init] works here but HOW?
    if(self = [self init]){
        //my custom stuff
    }
}

During writin this post I found that [super init] calls the -(instancetype)initWithContentURL:(NSURL *)contentURL and there lies the infinite loop problem. Why the designated initializer init calls the secondary initializer initWithURL? Should it not be the other way around? Please explain.

Does this mean I should put my code, that I don't want repeated, in the initWithURL method instead of the init method.

Edit: And that is what I did. I entered the code in the initWithURL method. Now both the default init and my custom init will run it.

2

There are 2 answers

3
FreeNickname On BEST ANSWER

Why do you call init a designated initializer? I believe, it is not. Let's refer to the docs:

The designated initializer plays an important role for a class. It ensures that inherited instance variables are initialized by invoking the designated initializer of the superclass. It is typically the init... method that has the most parameters and that does most of the initialization work, and it is the initializer that secondary initializers of the class invoke with messages to self.

So it doesn't seem to satisfy both characteristic: it has the least number of parameters and apparently it calls another initializer (initWithContentURL) with self. So, I believe, if you found the real designated initializer, everything would work as expected.

According to the MPMoviePlayerViewController class reference, the designated initializer is initWithContentURL. So you can simply override it instead of init.

1
ksh On

Just make a private method and put your common code there, like

- (void)commonInitialization {
    [self startWithHiddenControls];
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    [audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
    [audioSession setActive:YES error:nil];
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidEnterBackgroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(UIApplicationDidBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil];
}

and then use in your inits:

- (instancetype)initWithContentURL:(NSURL *)contentURL {
    self = [super initWithContentURL:contentURL];
    if (self) {
        [self commonInitialization];
        // everything else
    }
    return self;
}