Створити екземпляр класу object-c за іменем?


95

Чи можна створити екземпляр класу за іменем? Щось на зразок:

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

Я не знаю, чи можливо це в об’єкті-с, але, здається, це могло б бути,

Відповіді:



38

NSClassFromString()ризикує помилково ввести назву класу або іншим чином використовувати клас, який не існує. Ви не дізнаєтесь до часу виконання, якщо зробите цю помилку. Натомість, якщо ви використовуєте вбудований тип-c типу Classдля створення змінної, то компілятор перевірить наявність класу.

Наприклад, у вашому .h:

@property Class NameOfClass;

а потім у вашому .m:

id object = [[NameOfClass alloc] init];

Якщо ви неправильно ввели назву класу або якщо вона не існує, ви отримаєте помилку під час компіляції. Також я думаю, що це чистіший код.


ось ти дружище. Не зовсім впевнений, що це найкраща відповідь, оскільки він вимагає двох рядків і менш динамічний, але все одно проголосував
Кріс МакКолл,

Припускаю, що ви можете сказати, що це менш динамічно, оскільки я використовував символ замість рядка. Однак, якщо ви знаєте клас, який вам потрібен під час написання коду, то переважно використовувати символ, щоб уникнути можливих помилок.
Саймон Вудсайд,

@sbwoodside: Як це може працювати? Я спробував, і отримав "Невизначені символи для архітектури" від лінкера.
Ларс Шнайдер,

Змініть його на [[[самоклас] alloc] init]; Більше нічого не потрібно.
Нік Тернер

Приклад використання OP є більш ніж законним - він є базою для будь-якої серіалізації ієрархії об'єктів у файл / блок пам'яті / plist / що завгодно. Багато разів НАЗАД не знаєте заздалегідь, які класи потрібно буде створити. Моїм випадком використання є нудна потреба "зареєструвати" gazillion "NSValueTransformer" і замість дублювання [NSValueTransformer setValueTransformer: MyTransformerA alloc] init] forName: @ "MyTransformerA"]; 40 разів - я просто сканую NSArray імен трансформаторів - і створюю / реєструю їх із рядка.
Motti Shneor

8

Якщо ви працюєте з Objective-C без NeXTstep( OS X, iOS, і GNUstepт.д.) в системі або ви просто думаєте , що цей метод є більш чистим, то ви можете використовувати API Мови по Objective-C у час виконання бібліотеки . Під 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 ];

Під Objective-C (1.0 або неназвана версія) ви будете використовувати наступне:

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

Я не тестував 1.0версію, однак використовував 2.0функцію в коді, який зараз виготовляється. Я особисто вважаю , використовуючи 2.0функцію чистіше , якщо така є , ніж функція NS , як вона займає менше місця: the length of the name in bytes + 1 ( null terminator )для 2.0 API в порівнянні the sum of two pointers (isa, cstring), size_t length (cstring_length), а length of the string in bytes + 1для NeXTSTEPAPI.


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

@implementation Magic

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

@end

Потім, щоб використовувати його:

Car *car = [Magic createInstanceOfClass:[Car class]];
[car engineTurnOn];
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.