Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What if a class has no documented designated initializer?

I am looking for general guidance on how to handle this situation. Here is a specific example.

I am subclassing UIImageView and I want to override initWithImage to add my own initialization code after having the super class init itself with the supplied image.

However, there is no documented designated initializer for UIImageView, so which super class initializer should I call to ensure my subclass is correctly initialized?

If a class does not designate an initializer, do I:

  1. Assume that it is safe to call any of the class's (UIImageView) initializers?
  2. Look to the super class (UIView) for the designated initializer?

In this case it seems #1 would be the answer as it makes sense to do the following in my overridden initializer:

- (id)initWithImage:(UIImage *)image
{
    self = [super initWithImage:image];
    if (self) {
        // DO MY EXTRA INITIALIZATION HERE
    }
    return self;
}
like image 830
techsMex Avatar asked Oct 30 '12 20:10

techsMex


3 Answers

UIImageView has two initializers, so you may want to make sure that your subclass handles both of these initialization paths.

You could simply declare that -initWithImage: is your designated initializer, and all other initializers are not supported.

Further, you could implement -initWithImage:highlightedImage: and throw an exception to indicate that it's not supported.

Alternatively, you could declare -initWithImage:highlightedImage: as your designated initializer, and have -initWithImage: call your designated initializer.

Or, you may find that your -initWithImage: initializer is called regardless of whether your class is initialized with -initWithImage: or -initWithImage:highlightedImage:.

like image 116
Darren Avatar answered Nov 15 '22 17:11

Darren


UIImageView documentation is terrible. It shows two initializers but you can get in to situations where neither of them is called. For example, I am using IB and only initWithCoder: gets called.

- (id)init
{
    return [super init];
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    return [super initWithCoder:aDecoder];
}

- (id)initWithFrame:(CGRect)frame
{
    return [super initWithFrame:frame];
}

- (id)initWithImage:(UIImage *)image
{
    self = [super initWithImage:image];
    return self;
}

- (id)initWithImage:(UIImage *)image highlightedImage:(UIImage *)highlightedImage
{
    self = [super initWithImage:image highlightedImage:highlightedImage];
    return self;
}

The only correct way to subclass UIImageView is to subclass ALL initializers AND each subclass may ONLY call a parent's initializer with the same name. For example:

subclass -init can call UIImageView -init but it cannot call UIImageView -initWithCoder:.

Yes, it's a real pain that there is no designation.

like image 22
William Entriken Avatar answered Nov 15 '22 17:11

William Entriken


The danger when there's no designated initializer is that any of the initializers you might invoke could do its work in terms of one of the other initializers. In that case, it might accidentally call into one of your overrides, which won't work the way it's expected to.

If your class has exactly one initializer and it's an override of a superclass initializer, then it's safe for it to invoke the initializer that it overrode. That's because there's no chance that the super initializer will (directly or indirectly) re-enter itself, so there's no chance that it will re-enter your override.

Your class could also implement any number of initializers so long as none of them have the same name as any of the ones from the superclasses. Since your names are unique, there's no chance that any of the superclass initializers will call into them accidentally.

like image 42
Ken Thomases Avatar answered Nov 15 '22 18:11

Ken Thomases