2010-04-27 19 views
5

estoy corriendo en un tema extraño en Objective-C cuando tengo dos clases usando inicializadores del mismo nombre, pero los argumentos escritos de manera diferente. Por ejemplo, digamos que crear clases A y B:¿Los inicializadores de Objective-C tienen permitido compartir el mismo nombre?

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 

Bm:

#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; 
} 

Cuando ejecuto esto, me da el siguiente resultado:

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 

Si invierto el orden del las importaciones por lo que importa Bh primera, me sale:

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 

Por alguna razón, parece que se trata de utilizar el tipo de datos definido en lo que @interface se incluyó por primera vez para ambas clases. Hice algunos pasos a través del depurador y descubrí que el puntero isa para los objetos ayb termina igual. También descubrí que si yo ya no hago el alloc e init llamadas en línea, ambas inicializaciones parecen funcionar correctamente, por ejemplo:

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

Si utilizo esta convención cuando creo que tanto a como b, me sale la derecha salida y los punteros isa parecen ser diferentes para cada objeto.

¿Estoy haciendo algo mal? Hubiera pensado que varias clases podrían tener los mismos nombres de inicializador, pero quizás ese no sea el caso.

Respuesta

5

El problema es que el método +alloc devuelve un objeto de tipo id por lo que el compilador no puede decidir qué firma de método usar. Puede forzar a su aplicación a elegir el selector correcto de varias maneras. Una de ellas sería a emitir el regreso de alloc, por lo que:

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

o podría anular alloc en su clase y devolver algo más específico, a pesar de que yo no haría esto por mí mismo. Por lo tanto:

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

Por último, y lo que yo personalmente eligió, hago los selectores más descriptivo:

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

// B.h 
- (id)initWithInteger:(int)theNum; 
+1

También puede agregar estática 'typeWithArgument:' métodos, como '[NSNumber numberWithInt:]' para desambiguar – drawnonward

+0

De acuerdo con la documentación, el 'Ivar isa' debe establecerse cuando se llama' + [alloc NSObject] '. Dado que los envíos de mensajes de Objective-C se resuelven en tiempo de ejecución, no es que el trabajo del tiempo de ejecución, no el trabajo del compilador, de averiguar qué '+ [A alloc]' resuelve? –

+0

@Nick Forge: la implementación está vinculada dinámicamente, por lo que no es un problema (y eso es cierto aquí ya que el NSLog muestra A y B como se esperaba). Donde el compilador está involucrado está en construir la llamada a obj_msgSend. En este caso, un selector usa un flotante mientras que el otro usa un entero, y el compilador genera instrucciones diferentes (almacenando el int en un registro entero y el float en un registro fp). Debido a esto, la implementación del método encuentra datos erróneos en el registro esperado. –

Cuestiones relacionadas