Как мне получить класс Objective-C для ivar?

У меня есть куча простых NSManagedObject, которые я создаю в модульном тесте. У них есть только один атрибут name типа NSString *. Я всегда даю своему NSManagedObject одно и то же имя entityName и Class.

Я хочу избежать написания следующего кода 30 раз для настройки модульного теста:

@interface FooTest : GHTestCase {
Foo *foo;
}
@end
@implementation FooTest

- (void) setUp {
  [super setUp];

  foo = [NSEntityDescription insertNewObjectForEntityForName:@"Foo"
                                      inManagedObjectContext:managedObjectContext];
  foo.name = @"foo";
}
@end

Поскольку foo является иваром, я думаю, что должен написать макрос для захвата типа foo (Foo) и использовать его для создания моего Foo:

#define InsertManagedObjectByVariable(variable) \
do { \
variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])]; \
variable.name = (NSString *) CFSTR(#variable);
} while(0)

Однако это вызывает следующее предупреждение в clang:

variable = [NSEntityDescription insertNewObjectForEntityName:NSStringFromClass([typeof(variable) class])];
                                                                               ^
                                                             Expected expression

Я также подумал, что могу попытаться определить тип, используя среду выполнения target-c IVar из Ivar class_getInstanceVariable(Class cls, const char* name), но единственная информация о типе IVar, доступная из кодировки типа из ivar_getTypeEncoding, — это id, чего недостаточно.

Может ли кто-нибудь придумать способ получить информацию о типе IVar либо во время компиляции, либо во время выполнения?


person Heath Borders    schedule 29.06.2012    source источник
comment
Не проверял это, кроме как посмотреть, компилируется ли он, но не можете ли вы отказаться от typeof() и перейти к [variable class]?   -  person Phillip Mills    schedule 29.06.2012
comment
Нет, потому что variable равно нулю.   -  person Heath Borders    schedule 29.06.2012


Ответы (3)


Я не пытался получить информацию о классе из ivar, но я знаю, что объявления @property действительно кодируют информацию о классе. Например, это объявление свойства:

@property (copy) NSString *normalString;

приводит к этой строке атрибута (полученной с помощью property_getAttributes( )) во время выполнения:

T@"NSString",C,VnormalString

Я написал некоторый код синтаксического анализа с открытым исходным кодом для этого Информация.

Получив имя класса, вы можете преобразовать его в фактический объект класса, используя NSClassFromString() и оттуда сообщите результат.

Отказ от ответственности: на это, вероятно, не следует полагаться для рабочих приложений, так как это недокументировано.

person Justin Spahr-Summers    schedule 29.06.2012
comment
Потрясающий. Когда я писал этот вопрос, я знал, что вы знаете ответ. :) - person Heath Borders; 30.06.2012
comment
Очень интересные вещи. Включение типа в виде строки не задокументировано; Вы случайно не знаете, когда он был введен? - person Rob Napier; 09.07.2012
comment
@RobNapier Хм, действительно понятия не имею. Он работал в Clang/Objective-C 2.0 столько, сколько я пробовал. Вероятно, не очень хорошая идея полагаться на него для производственного кода, но очень полезно для решения для тестирования, подобного этому. - person Justin Spahr-Summers; 09.07.2012
comment
На самом деле это задокументировано в Руководство по работе с программой. Этот документ не менялся с 2009 года. - person Cris; 10.07.2012
comment
@Cris Это верно для большей части синтаксиса, но я полагаю, что Роб Напье имел в виду конкретно информацию о классе в типе (которая не упоминается и не показана в примере). - person Justin Spahr-Summers; 10.07.2012
comment
Хорошо, я понимаю, что вы имеете в виду. Это не столько не-, сколько смутно задокументировано. В документе явно указано, что за T следует тип @encode, но формат не идентичен тому, что создает @encode, и в документе есть примеры только для типа id. - person Cris; 10.07.2012

id есть id. Во время выполнения все объекты Objective-C имеют один и тот же тип (objc_object). Это связано с динамической природой ObjC. Например, объект может изменять классы во время выполнения, могут создаваться новые классы и может изменяться иерархия классов. Вы можете спросить конкретный экземпляр, каков его тип (поскольку он хранится в objc_object), но указатель на объект — это просто указатель на объект. Даже меньше: на самом деле это просто указатель на структуру C, которая имеет дополнительную память, выделенную в конце (для хранения переменных подклассов).

Ваш макрос кажется интересным, но вам, вероятно, потребуется передать имя класса в качестве второго параметра, а не автоматически определять его.

person Rob Napier    schedule 29.06.2012
comment
Спасибо. Да, я пытался обрисовать это в своем вопросе. Я надеюсь, что кто-то с сумасшедшими навыками препроцессора C увидит это и поймет, как превратить typeof() в выражение. - person Heath Borders; 29.06.2012

Может быть, я неправильно понимаю, чего вы пытаетесь достичь. Чтобы получить класс iVar, нельзя ли использовать метод class iVar?

как:

NSString *aString = @"random string";
NSLog(@"%@",NSStringFromClass([aString class]));
person Just a coder    schedule 29.06.2012
comment
Не будет работать, если значение ivar равно нулю, как в случае с вопросом. - person rob mayoff; 29.06.2012