Créer une instance de classe objective-c par son nom?


95

Est-il possible de créer une instance d'une classe par son nom? Quelque chose comme:

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

Je ne sais pas si cela est possible dans objective-c mais il semble que ce serait le cas,

Réponses:



38

NSClassFromString()court le risque de mal saisir le nom de la classe ou d'utiliser autrement une classe qui n'existe pas. Vous ne saurez pas avant l'exécution si vous faites cette erreur. Au lieu de cela, si vous utilisez le type objectif-c intégré Classpour créer une variable, le compilateur vérifiera que la classe existe.

Par exemple, dans votre .h:

@property Class NameOfClass;

puis dans votre .m:

id object = [[NameOfClass alloc] init];

Si vous avez mal saisi le nom de la classe ou s'il n'existe pas, vous obtiendrez une erreur lors de la compilation. Je pense aussi que c'est un code plus propre.


voilà, mon pote. Pas tout à fait sûr que ce soit la meilleure réponse, car elle nécessite deux lignes et est moins dynamique, mais a tout de même voté pour
Chris McCall

Je suppose que vous pourriez dire que c'est moins dynamique parce que j'ai utilisé un symbole au lieu d'une chaîne. Cependant, si vous connaissez la classe souhaitée lorsque vous écrivez le code, il est préférable d'utiliser le symbole afin d'éviter d'éventuelles fautes de frappe.
Simon Woodside

@sbwoodside: Comment cela peut-il fonctionner? Je l'ai essayé et j'ai obtenu "Symboles non définis pour l'architecture" de l'éditeur de liens.
Lars Schneider

Changez-le en [[[self class] alloc] init]; Vous n'avez besoin de rien d'autre.
Nick Turner

Le cas d'utilisation de l'OP est plus que légitime - c'est la base de toute sérialisation de la hiérarchie d'objets en fichier / bloc-mémoire / plist / peu importe. Plusieurs fois, vous NE SAVEZ PAS à l'avance quelles classes vous devrez instancier. Mon cas d'utilisation est le besoin fastidieux de "enregistrer" des millions de "NSValueTransformer" s et au lieu de dupliquer [NSValueTransformer setValueTransformer: MyTransformerA alloc] init] forName: @ "MyTransformerA"]; 40 fois - je scanne juste un NSArray de noms de transformateurs - et les crée / les enregistre à partir d'une chaîne.
Motti Shneor

8

Si vous travaillez avec Objective-C sans NeXTstep( OS X, iOS, GNUstepetc.) ou système vous pensez que cette méthode est plus propre, vous pouvez utiliser l' API de bibliothèque d'exécution de langage Objective-C . Sous 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 ];

Sous Objective-C (version 1.0 ou sans nom), vous utiliseriez ce qui suit:

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

Je n'ai pas testé la 1.0version, cependant j'ai utilisé la 2.0fonction dans le code qui est maintenant en production. Personnellement, je pense que l'utilisation de la 2.0fonction est plus propre si elle est disponible que la fonction NS car elle consomme moins d'espace: the length of the name in bytes + 1 ( null terminator )pour l'API 2.0 par rapport à the sum of two pointers (isa, cstring), a size_t length (cstring_length)et length of the string in bytes + 1pour l' NeXTSTEPAPI.


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

@implementation Magic

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

@end

Alors pour l'utiliser:

Car *car = [Magic createInstanceOfClass:[Car class]];
[car engineTurnOn];
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.