Arasch Honarbacht
Arasch Honarbacht

Reputation: 53

Objective-C: How to avoid unintended calls to private superclass methods with identical name?

I'm trying to avoid duplicate code in various -(id)init flavors of a class, i.e. init, initWithFrame, initWithCoder, etc. by defining a private method that is named commonConstruct.

This method does the heavy lifting common to all init method flavors and gets called by the init constructor.

The issue i have now is that in derived classes, using the same naming convection for the initializer helper ("commonConstruct") the base class will call the derived class's commonConstruct, though it is invisible, i.e. declared in the .m file, not in the .h file.

However, the runtime finds the overloaded commonConstruct and executes that instead of its own member function.

Is there any other way than using a different name for the initializer helper in each subclass ?

In other words: Is there a way of making Objective-C member functions that are "non-virtual", i.e. don't have late (runtime) but compile-time binding?

Upvotes: 5

Views: 243

Answers (2)

Nikolai Ruhe
Nikolai Ruhe

Reputation: 81868

In addition to Rob Mayoff's solution (which I use as well) you could use a static C function:

@implementation Thing
{
    id _privateIvar;
}

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

- (id)initWithArgument:(id)argument
{
    return commonInit([super init], argument);
}

static Thing *commonInit(Thing *self, id argument)
{
    if (self == nil)
        return nil;
    self->_privateIvar = argument;
    return self;
}

@end

Static functions don't emit symbols, so there are no possible conflicts. You can name all of your common initializers commonInit.

Upvotes: 3

rob mayoff
rob mayoff

Reputation: 385890

There's no good compiler-enforced way to do this. Methods are always “virtual” and there is no enforcement of “private” methods.

The common solution is to embed the class name in the method name, thus:

@implementation Thing

- (instancetype)init {
    if (self = [super init]) {
        [self Thing_commonInit];
    }
    return self;
}

- (instancetype)initWithArg:(NSObject *)arg {
    if (self = [super init]) {
        [self Thing_commonInit];
        [self doSomethingWithArg:arg];
    }
    return self;
}

- (void)Thing_commonInit {
    ...
}

Upvotes: 4

Related Questions