Создать экземпляр класса objective-c по имени?


95

Можно ли создать экземпляр класса по имени? Что-то вроде:

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

Я не знаю, возможно ли это в objective-c, но похоже, что это было бы,

Ответы:



38

NSClassFromString()рискует ошибиться при вводе имени класса или иным образом использовать несуществующий класс. Вы не узнаете до времени выполнения, если сделаете эту ошибку. Вместо этого, если вы используете встроенный тип objective-c Classдля создания переменной, компилятор проверит, существует ли класс.

Например, в вашем .h:

@property Class NameOfClass;

а затем в вашем .m:

id object = [[NameOfClass alloc] init];

Если вы неправильно набрали имя класса или он не существует, вы получите ошибку во время компиляции. Также я думаю, что это более чистый код.


вот так, приятель. Не совсем уверен, что это лучший ответ, так как он требует двух строк и менее динамичен, но все равно получил голосование
Крис МакКолл,

Я полагаю, вы могли бы сказать, что он менее динамичен, потому что я использовал символ вместо строки. Однако, если вы знаете, какой класс вам нужен при написании кода, тогда предпочтительнее использовать символ, чтобы избежать возможных опечаток.
Саймон Вудсайд

@sbwoodside: Как это может работать? Я попробовал и получил от компоновщика «Неопределенные символы для архитектуры».
Lars Schneider

Измените его на [[[self class] alloc] init]; Больше тебе ничего не нужно.
Ник Тернер,

Вариант использования OP более чем законен - ​​это основа для любой сериализации иерархии объектов в файл / блок памяти / plist / что угодно. Часто вы НЕ ЗНАЕТЕ заранее, какие классы вам нужно создать. Мой вариант использования - утомительная необходимость "зарегистрировать" gazillion "NSValueTransformer" вместо дублирования [NSValueTransformer setValueTransformer: MyTransformerA alloc] init] forName: @ "MyTransformerA"]; 40 раз - я просто просматриваю NSArray имен трансформаторов - и создаю / регистрирую их из строки.
Мотти Шнеор

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 )для API 2.0 по сравнению с the sum of two pointers (isa, cstring)a 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.