Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Objective-C initializers allowed to share the same name?

I'm running into an odd issue in Objective-C when I have two classes using initializers of the same name, but differently-typed arguments. For example, let's say I create classes A and B:

A.h:

#import <Cocoa/Cocoa.h>

@interface A : NSObject {
}

- (id)initWithNum:(float)theNum;

@end

A.m:

#import "A.h"

@implementation A

- (id)initWithNum:(float)theNum
{
    self = [super init];
    if (self != nil) {
        NSLog(@"A: %f", theNum);
    }
    return self;
}

@end

B.h:

#import <Cocoa/Cocoa.h>

@interface B : NSObject { 
}

- (id)initWithNum:(int)theNum;

@end

B.m:

#import "B.h"

@implementation B

- (id)initWithNum:(int)theNum
{
    self = [super init];
    if (self != nil) {
        NSLog(@"B: %d", theNum);
    }
    return self;
}

@end

main.m:

#import <Foundation/Foundation.h>

#import "A.h"
#import "B.h"

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    A *a = [[A alloc] initWithNum:20.0f];   
    B *b = [[B alloc] initWithNum:10];

    [a release];
    [b release];

    [pool drain];
    return 0;
}

When I run this, I get the following output:

2010-04-26 20:44:06.820 FnTest[14617:a0f] A: 20.000000
2010-04-26 20:44:06.823 FnTest[14617:a0f] B: 1

If I reverse the order of the imports so it imports B.h first, I get:

2010-04-26 20:45:03.034 FnTest[14635:a0f] A: 0.000000
2010-04-26 20:45:03.038 FnTest[14635:a0f] B: 10

For some reason, it seems like it's using the data type defined in whichever @interface gets included first for both classes. I did some stepping through the debugger and found that the isa pointer for both a and b objects ends up the same. I also found out that if I no longer make the alloc and init calls inline, both initializations seem to work properly, e.g.:

A *a = [A alloc];
[a initWithNum:20.0f];

If I use this convention when I create both a and b, I get the right output and the isa pointers seem to be different for each object.

Am I doing something wrong? I would have thought multiple classes could have the same initializer names, but perhaps that is not the case.

like image 500
NattKatt Avatar asked Apr 27 '10 01:04

NattKatt


1 Answers

The problem is that the +alloc method returns an object of type id so the compiler can't decide which method signature to use. You can force your application to choose the correct selector in a number of ways. One would be to cast the return from alloc, so:

A* a = [(A*)[A alloc] initWithNum:20.f];
B* b = [(B*)[B alloc] initWithNum:10];

Or you could override alloc on your class and return something more specific, although I wouldn't do this myself. So:

+ (A*)alloc { return [super alloc]; }

Finally, and what I would personally chose, make the selectors more descriptive:

// A.h
- (id)initWithFloat:(float)theNum;

// B.h
- (id)initWithInteger:(int)theNum;
like image 57
Jason Coco Avatar answered Oct 22 '22 17:10

Jason Coco