Приведение объекта типа id к неизвестному типу во время выполнения

У меня есть метод, который принимает в качестве строки имя объекта в моей базе данных sqlite, который я пытаюсь упростить, чтобы использовать как можно меньше повторяющегося кода.

здесь у меня есть сущность в качестве идентификатора, которую я пытаюсь установить для требуемого типа объекта в готовности сделать вызов для вставки строки.

проблема заключается в том, когда я делаю вызов сущности NSEntityDescription все еще с идентификатором класса

  id entity;

if ([entityName isEqualToString:@"yadda yadda"]) {

    entity = [EntityYadda class];
}
else if ([entityName isEqualToString:@"blah blah"]) {

    entity = [EntityBlah class];
}
else if ([entityName isEqualToString:@"Foobar"]) {

    entity = [EntityFoobar class];
}

for (int x=0; x<[data count]; x++) {

    entity = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];

Куда я иду не так?

Спасибо

3 ответа

Решение

У меня есть 7 разных сущностей с одинаковыми полями, поэтому я пытаюсь динамически назначить требуемый класс сущностей для "сущности", поэтому в моем цикле у меня будет только одна строка, использующая NSEntityDescription и настройки свойств.

Что ж, у вас уже была мысль "почему бы не один объект с полем флага, обозначающим тип?", И это отличный вопрос, и я очень рекомендую пойти по этому пути.

Если по какой-либо причине вы не можете, вы можете объявить идентичные поля в протоколе, а затем объявить, что все эти 7 объектов соответствуют одному и тому же протоколу. В вашем методе ваше объявление типа будет (вместо id): NSManagedObject<MyCustomProtocol> *,

Почему бы вам не создать typedef:

typedef enum {

EntityTypeYaddaYadda,
EntityTypeBlahBlah,
    EntityTypeFoobar

} EntityType;

Затем выполните переключение:

for (int x=0; x<[data count]; x++) {

switch (entity.entityType){
case EntityTypeYaddaYadda:
{
YaddaYadda *yaddaYaddaObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
... set properties...
}
break;

case EntityTypeBlahBlah:
{
BlahBlah *blahBlahObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
... set properties...
}
break;

case EntityTypeFoobar:
{
Foobar *foobarObject = [NSEntityDescription insertNewObjectForEntityForName:entityName inManagedObjectContext:context];
... set properties...
}
break;
}

Затем сохраните свой контекст:

if (![managedObjectContext save:&error]) {
NSLog(@"Error while saving.");
}

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

Я не гуру, но насколько я знаю, есть только 2 способа объявления переменных:

  1. используя статическую типизацию (когда вы объявляете тип вашей переменной: UIView *myview)
  2. используя динамическую типизацию (когда вы объявляете переменную с помощью "id": id myObject)

В первом случае тип известен во время компиляции, и компилятор выполнит серию проверок для обеспечения согласованности в вашем коде. Во втором случае тип не известен, пока во время выполнения. В любом случае, после того, как вы определили тип переменной (используя идентификатор или конкретное имя класса), переопределить его невозможно.

В любом случае вы можете динамически назначать классы, используя NSSClassFromString(), избегая длинных операторов if/else или switch.

Более того, вы можете (должны) использовать такие инструменты, как RespondsToSelector:(SEL), чтобы гарантировать, что вы отправите сообщение классу безопасно

Другие вопросы по тегам