2008-11-24 13 views
15

Estoy trabajando en una fábrica de objetos para realizar un seguimiento de una pequeña colección de objetos. Los objetos pueden ser de tipos diferentes, pero todos responderán a createInstance y reset. Los objetos no se pueden derivar de una clase base común porque algunos de ellos deberán derivarse de clases incorporadas de cacao como NSView y NSWindowController.¿Cómo puedo pasar un nombre de clase como argumento a una fábrica de objetos en cacao?

Me gustaría ser capaz de crear instancias de cualquier objeto adecuado simplemente pasando el nombre de clase deseada a mi fábrica de la siguiente manera:

myClass * variable = [factory makeObjectOfClass:myClass];

El método makeObjectOfClass: sería algo como esto:

- (id)makeObjectOfClass:(CLASSNAME)className 
{ 
    assert([className instancesRespondToSelector:@selector(reset)]); 
    id newInstance = [className createInstance]; 
    [managedObjects addObject:newInstance]; 
    return newInstance; 
}

¿Hay alguna manera de pasar un nombre de clase a un método, como he hecho con el argumento (CLASSNAME)className al makeObjectOfClass: anterior?

Para completar, aquí es por qué quiero administrar todos los objetos. Quiero poder restablecer el conjunto completo de objetos en una sola toma, llamando al [factory reset];.

- (void)reset 
{ 
    [managedObjects makeObjectsPerformSelector:@selector(reset)]; 
}
+0

Estoy dividido entre Michael Tsai y respuestas de Matt Gallagher. Subí ambos, ya que ambos mencionan el uso de 'Clase', que es lo que estaba buscando. Al final, elegí la respuesta de Matt porque enfatiza 'Clase' sobre ClassFromString, y fue el primero en mencionar el uso de 'Clase' antes de las ediciones. –

+0

@Ned Batchelder: Gracias por cambiar la etiqueta. Por alguna razón, 'objectivec' muestra muchos más elementos (alrededor de 200) que 'objetivo-c' en la lista desplegable de etiquetas que aparece cuando agregué etiquetas a la pregunta, pero ahora veo que 'objectivec' ha sido redirigido a 'objetivo-c' –

+0

@eJames: Su pregunta muestra -reset enviado a instancias, no el objeto de clase, por lo que creo que [aClass respondsToSelector: @selector (reset)] en la respuesta de Matt Gallagher es incorrecto. –

Respuesta

22

Puede convertir una cadena a una clase usando la función: NSClassFromString

Class classFromString = NSClassFromString(@"MyClass"); 

En su caso, sin embargo, sería mejor usar la clase objetos directamente.

MyClass * variable = [factory makeObjectOfClass:[MyClass class]]; 

- (id)makeObjectOfClass:(Class)aClass 
{ 
    assert([aClass instancesRespondToSelector:@selector(reset)]); 
    id newInstance = [aClass createInstance]; 
    [managedObjects addObject:newInstance]; 
    return newInstance; 
} 
+0

El tipo 'Clase' y [Clase MyClass] es exactamente lo que estaba buscando. ¡Gracias! –

+0

Michael Tsai ha señalado que la línea [aClass respondsToSelector: @selector (reset)] debería leer [aClass instancesRespondToSelector: @selector (reset)]. Estoy haciendo el cambio en mi pregunta, es posible que desee hacer lo mismo en su respuesta. –

2

Parece que usted quiere algo como:

- (id)makeObjectOfClassNamed:(NSString *)className 
{ 
    Class klass = NSClassFromString(className); 
    assert([klass instancesRespondToSelector:@selector(reset)]); 
    id newInstance = [klass createInstance]; 
    [managedObjects addObject:newInstance]; 
    return newInstance; 
} 

Este asumiría un método de clase llamado +createInstance. O simplemente podría usar [[klass alloc] init].

Llamarlo:

MyClass *variable = [factory makeObjectOfClassNamed:@"MyClass"]; 

Dependiendo de lo que estamos tratando de hacer, tal vez sería mejor para pasar alrededor de objetos de clase que las cuerdas, por ejemplo:

MyClass *variable = [factory makeObjectOfClass:[MyClass class]]; 
+0

Gracias por su respuesta. Usaré el enfoque [Clase MyClass] que mencionaste en tu edición. –

+0

A menos que esté compilando para Objective-C++, puede nombrar las variables "clase". – cncool

3

Es bastante fácil dinámicamente especificar una clase, de hecho, sólo se puede hacer referencia a ella por su nombre:

id string = [[NSClassFromString(@"NSString") alloc] initWithString:@"Hello!"]; 
NSLog(@"%@", string); 

otro consejo, lo haría una nulo usando la nomenclatura 'objeto gestionado' ya que la mayoría de los demás programadores de Cocoa lo leerán como NSManagedObject, desde Core Data. También puede resultarle más fácil utilizar una NSNotificación global (a la que se suscriben todos los objetos restaurables) en lugar de administrar una colección de diferentes tipos de objetos, pero está más informado que yo para tomar esa decisión.

+0

buen punto sobre NSManagedObject. Cambiaré mi pregunta para evitar la posible confusión. –

3

El bit de la respuesta que falta de las otras respuestas es que se podría definir un @protocol que contiene sus +createInstance y +reset métodos.

+0

¡Gracias por el consejo! Estoy planeando usar un protocolo, pero no sentí la necesidad de mencionarlo en la pregunta. –

Cuestiones relacionadas