Creare un'istanza di classe Objective-C per nome?


95

È possibile creare un'istanza di una classe per nome? Qualcosa di simile a:

NSString* className = @"Car";
id* p = [Magic createClassByName:className];
[p turnOnEngine];

Non so se questo sia possibile nell'obiettivo-c ma sembra che lo sarebbe,

Risposte:



38

NSClassFromString()corre il rischio di digitare in modo errato il nome della classe o altrimenti di utilizzare una classe che non esiste. Non lo scoprirai fino al runtime se commetti quell'errore. Se invece utilizzi il tipo di object-c incorporato Classper creare una variabile, il compilatore verificherà che la classe esista.

Ad esempio, nel tuo .h:

@property Class NameOfClass;

e poi nel tuo .m:

id object = [[NameOfClass alloc] init];

Se hai digitato male il nome della classe o se non esiste, riceverai un errore in fase di compilazione. Inoltre penso che questo sia un codice più pulito.


ecco qua, amico. Non del tutto sicuro che sia la risposta migliore, in quanto richiede due righe ed è meno dinamico, ma è ugualmente votato
Chris McCall

Suppongo si possa dire che è meno dinamico perché ho usato un simbolo invece di una stringa. Tuttavia, se si conosce la classe che si desidera quando si scrive il codice, è preferibile utilizzare il simbolo in modo da evitare possibili errori di battitura.
Simon Woodside,

@sbwoodside: come può funzionare? L'ho provato e ho ottenuto "Simboli non definiti per l'architettura" dal linker.
Lars Schneider

Cambialo in [[[self class] alloc] init]; Non hai bisogno di nient'altro.
Nick Turner

Il caso d'uso dell'OP è più che legittimo: è la base per qualsiasi serializzazione della gerarchia degli oggetti in file / memory-block / plist / qualunque cosa. Molte volte NON SAPETE in anticipo quali classi avrete bisogno di istanziare. Il mio caso d'uso è la noiosa necessità di "registrare" miliardi di "NSValueTransformer" e invece di duplicare [NSValueTransformer setValueTransformer: MyTransformerA alloc] init] forName: @ "MyTransformerA"]; 40 volte: eseguo la scansione di un NSArray di nomi di trasformatori e li creo / li registro da una stringa.
Motti Shneor

8

Se si lavora con Objective-C, senza la NeXTstep( OS X, iOS, GNUstepsistema ecc) o semplicemente pensi che questo metodo è più pulita, allora si potrebbe utilizzare l' API di libreria di runtime linguaggio Objective-C . Sotto Objective-C 2.0:

#import <objc/runtime.h>
//Declaration in the above named file
id objc_getClass(const char* name);
//Usage
id c = objc_getClass("Object");
[ [ c alloc ] free ];

Sotto Objective-C (1.0 o versione senza nome) utilizzeresti quanto segue:

#import <objc/objc-api.h>
//Declaration within the above named file
Class objc_get_class( const char* name);
//Usage
Class cls = objc_get_class( "Test" );
id obj = class_create_instance( cls );
[ obj free ];

Non ho testato la 1.0versione, tuttavia ho utilizzato la 2.0funzione nel codice che è ora in produzione. Personalmente ritengo che l'utilizzo della 2.0funzione sia più pulito se disponibile rispetto alla funzione NS in quanto consuma meno spazio: the length of the name in bytes + 1 ( null terminator )per l'API 2.0 rispetto the sum of two pointers (isa, cstring)a size_t length (cstring_length), a e length of the string in bytes + 1per l' NeXTSTEPAPI.


2
@interface Magic : NSObject
+ (id)createInstanceOfClass:(Class)classe;
@end

@implementation Magic

+ (id)createInstanceOfClass:(Class)classe
{
    return [[classe alloc] init];
}

@end

Quindi per usarlo:

Car *car = [Magic createInstanceOfClass:[Car class]];
[car engineTurnOn];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.