Приведение объекта типа 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 способа объявления переменных:
- используя статическую типизацию (когда вы объявляете тип вашей переменной: UIView *myview)
- используя динамическую типизацию (когда вы объявляете переменную с помощью "id": id myObject)
В первом случае тип известен во время компиляции, и компилятор выполнит серию проверок для обеспечения согласованности в вашем коде. Во втором случае тип не известен, пока во время выполнения. В любом случае, после того, как вы определили тип переменной (используя идентификатор или конкретное имя класса), переопределить его невозможно.
В любом случае вы можете динамически назначать классы, используя NSSClassFromString(), избегая длинных операторов if/else или switch.
Более того, вы можете (должны) использовать такие инструменты, как RespondsToSelector:(SEL), чтобы гарантировать, что вы отправите сообщение классу безопасно