简体   繁体   中英

OK to have two designated initializers?

I have the following in a subclass of UIViewController;

- (id) initWithFullScreen
{
    self = [super initWithNibName:nil bundle:nil];

    if (self) 
    {
        _fullScreen = YES;
    }

    return self;     
}
- (id) init
{
    self = [super initWithNibName:nil bundle:nil];

    if (self) 
    {
        _fullScreen = NO;
    }

    return self; 
}

- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil 
{
    return [self init];
}

As you can see they aren't all chained together like recommended as there are two initializers that call the super classes designated initializer. Is this OK to do?

Why not do it this way instead:

- (id)initWithFullScreen:(BOOL)useFullScreen
{
  self = [super initWithNibName:nil bundle:nil];
  if(self) {
    _fullScreen = useFullScreen;
  }
  return self;
}

- (id)init
{
  return [self initWithFullScreen:NO];
}

- (id)initWithNibNameBlahBlahBlah...
{
  return [self init];
}

Yes, it's OK.

A designated initializer isn't part of the Objective-C language, it's just a convention. In general, if you route everything through one init method, your don't have to worry about duplicating code across all the other convenience init methods that you might want to offer.

It also lets you know which init method you should call on the superclass when you want to create a subclass. (Your third init method, initWithNibName... violates this rule, actually. Instead of calling the superclass's designated initializer, you're just calling init .)

In your case, declaring an initializer with the method signature initWithFullScreen:(BOOL)fullScreen and designating it the designated initializer is probably the way to go. And within that you make sure you call the superclass's designated initializer, which you are.

You could then create convenience initializers: initWithFullScreen and initWithoutFullScreen if you wanted to; they would both just call your designated initializer. For example:

- (id)initWithoutFullScreen
{
    return [self initWithFullScreen:NO];
}

So, it's OK to break the convention. You may have your reasons. But it's generally easier to keep your code organized if you stick to it.

Amendment

For extra credit, consider the NSCoding protocol, which requires classes to have an initWithCoder: method. One might say it violates the rule, since classes which adopt NSCoding and whose superclasses also adopt NSCoding must be prepared to have two paths to initialization: an initWithCoder: method which calls [super initWithCoder:coder] and the regular designated initializer.

Think of them as methods rather than initializers . So yes you can have as many methods as you want.
Also try to utilize nibNameOrNil and nibBundleOrNil in initWithFullScreen and init unless you really don't need them.
Also for simplicity you can have a method like this

- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil fullScreen:(BOOL)useFullScreen
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
      {
         _fullScreen = useFullScreen;
      }
    return self;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM