При отражении: следует установить свойство или напрямую установить значение? (Цель-С)

Я пишу класс сериализации xml для target-c.
Суть в том, чтобы дать классу тип класса и файл xml. Он должен вернуть экземпляр с данными.

У меня он работает, и он делает совсем немного - обрабатывает примитивы (+nsstring), определяемые пользователем классы и nsarrays. Не обрабатывает указатели или C-массивы.
Очевидно, что это в значительной степени зависит от отражения.

Вопрос: когда я устанавливаю значение экземпляра некоторого класса, должен ли я проверять, существует ли свойство с правильным именем, или я могу просто установить переменную с помощью простого отражения?

Это код, который я использовал до сих пор:

id newClass = class_createInstance(NSClassFromString(elementName), sizeof(unsigned));
Ivar nameVar = class_getInstanceVariable([newClass class], "name");
if (nameVar != nil)
    object_setIvar(newClass, nameVar, [NSString stringWithString:@"George"]);

Кроме того, после такого задания я должен что-то выпускать?


person Dror Speiser    schedule 06.09.2009    source источник
comment
Почему вы не используете NSKeyedArchiver для этого? или КорДата?   -  person Kornel    schedule 07.09.2009


Ответы (1)


Хм... обычно вам не нужно так глубоко погружаться в среду выполнения, чтобы делать то, что делает этот код. Следующее полностью функционально и делает то же самое:

id newObject = [[NSClassFromString(elementName) alloc] init];
@try {
  [newObject setValue:@"George" forKey:@"name"];
@catch (NSException *e) {
  if ([[e name] isEqualToString:NSUndefinedKeyException]) {
    NSLog(@"%@ does not recognize the property \"name\"", elementName);
  }
}

//... do stuff with newObject
[newObject release];

Если вам нужно добавить другие элементы, такие как числа с плавающей запятой, целые числа или структуры, вы можете упаковать их в NSValue (или подкласс), а затем передать их в setValue:forKey:. Например:

NSNumber * aFloat = [NSNumber numberWithFloat:42.0];
[newObject setValue:aFloat forKey:@"aFloatIvar"];

NSRect frame = NSMakeRect(0, 0, 42, 54);
NSValue * aStruct = [NSValue valueWithBytes:&frame objcType:@encode(NSRect)];
[newObject setValue:aStruct forKey:@"aStructIvar"];
person Dave DeLong    schedule 06.09.2009
comment
Проблема с этим кодом в том, что он не работает для примитивных типов. Есть ли способ это исправить? - person Dror Speiser; 07.09.2009
comment
Поместите свои примитивы в объект NSValue (например, NSValue или NSNumber), и внутренние компоненты автоматически распакуют их. - person Dave DeLong; 07.09.2009
comment
NSValue хочет тип objCType:(const char *). Как получить тип? (Предполагая, что без class_getInstanceVariable) - person Dror Speiser; 08.09.2009
comment
Код предполагает предварительное знание типа (float, NSRect). Есть ли простой способ получить примитивный тип переменной класса, чтобы я мог включить его, чтобы сделать вышеописанное? - person Dror Speiser; 08.09.2009
comment
@ Дрор, я не знаю. Что вы пытаетесь сделать с этим? - person Dave DeLong; 08.09.2009
comment
@DaveDeLong - это многообещающе для меня и может быть моим ответом, если бы я полностью понял это прямо сейчас. Я впитываю информацию здесь. Но если вы так склонны дать мне другой ответ, чтобы получить больше очков, см. мой вопрос здесь: - person Patricia; 28.08.2014