Ошибка Weird Switch в Obj-C
У меня есть оператор switch в моем коде:
switch(buttonIndex){
case 0:
[actionSheet dismissWithClickedButtonIndex:buttonIndex animated:YES];
break;
case 1:
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:[imagePicker autorelease] animated:YES];
break;
default:
[self openEmailViewInViewController:self];
}
И при создании экземпляра UIImagePickerController в случае 1 я получаю сообщение об ошибке:
error:expected expression before 'UIImagePickerController'
и я понятия не имею, что я делаю неправильно. Мысли?
Oh, а buttonIndex - NSInteger
Ответы
Ответ 2
Я столкнулся с этой проблемой, и в один прекрасный день я решил в нее заглянуть.
Короткое, не ответное, но прагматичное решение:
Способ обойти эту "проблему" - это использовать двоеточие, ;, сразу после двоеточия оператора case ...:. Например, используя предоставленный вами пример, он может быть "исправлен", поэтому он компилируется и ведет себя так, как вы бы интуитивно ожидали его:
case 1:; // <- Note semi-colon.
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
Длинный ответ:
Некоторая история. Раньше C разрешало вам объявлять "блокировать локальные" переменные в начале блока, за которым последовали различные утверждения. C99 изменил ситуацию, чтобы вы могли свободно смешивать объявления переменных и утверждения.
В контексте грамматики C99 BNF объявление переменной - это declaration, а инструкция - statement. A statement означает несколько вещей, один из них известен как compound-statement, который является знакомым блоком { ... }. Часть ... свободно определяется как zero or more block-items, при этом block-item определяется свободно как either a declaration or a statement.
Проблема заключается в том, что a labeled-statement (метка goto, метка case или default:, по существу, операторы ...:), которая определена слабо ...: zero or more statementsя > . Это не так, как можно было бы ожидать интуитивно, zero or more statements or declarations. Использование ; сразу после labeled-statement : по существу завершает часть zero or more statements a labeled-statement. Это приводит к тому, что грамматика возвращается к определению compound-statement, которое позволяет следующему "утверждению" быть либо statement, либо declaration.
Я не исследовал, является ли это непреднамеренным просмотром спецификации языка C99 (на практике, ошибка в стандарте C99) или если это прагматичная уступка сложностям написания языковых грамматик. Если вы не знакомы с написанием грамматик, вы заметите, что приведенное выше объяснение допускает рекурсию: A labeled-statement может соответствовать case 1: case 2: case 3:. В чрезмерно упрощенных терминах (1) некоторые типы рекурсии грамматики просты и "однозначны", а другие сложны и "неоднозначны". Для простоты большинство языковых инструментов будут обрабатывать только случай, когда любая двусмысленность должна быть детерминистически решена, рассматривая не что иное, как "следующий токен". Я упоминаю об этом только потому, что, хотя это может показаться интуитивно недостаточным в спецификации C99, могут быть убедительные, неочевидные причины, почему это существует... и я не потрудился провести дальнейшие исследования по этому вопросу, чтобы узнать в любом случае.
(1) Это не должно быть технически точным описанием, но разумным приближением для тех, кто не знаком с проблемами.
EDIT:
Решение, которое я дал, работает в "большинстве" случаев (случаи "обычаи", а не switch case s), но в одном случае это не работает: это не будет работать, если декларация объявит C99 variable length array, например case 1:; void *ptrs[count]; Это связано с тем, что в C99 ошибка "проскользнуть" после объявления VLA C99, которая находится в той же лексической области, где произошел скачок. В этих случаях вам нужно использовать case 1: { void *ptrs[count]; }. В этом случае область действия ptrs VLA заканчивается на закрытии }. Это сложнее, чем в первую очередь, потому что следующее является совершенно законным кодом C, хотя на первый взгляд интуитивно подумать, что это не так:
switch(3){
case 0:
printf("case 0\n");
break;
case 1:;
int *ip = NULL;
printf("case 1\n");
break;
case 2:
{
int ia[6];
printf("case 2\n");
break;
case 3:
printf("case 3\n");
break;
default:
printf("default\n");
}
}
Это компилируется и при запуске печатает case 3.
Смотрите также: Википедия: устройство Duffs
Ответ 3
Одна вещь, которую мне нравится делать в этой ситуации, - это разместить содержимое каждого case в фигурных скобках. Это разрешено компилятором:
switch (buttonIndex)
{
case 0:
{
[actionSheet dismissWithClickedButtonIndex:buttonIndex animated:YES];
break;
}
case 1:
{
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
[self presentModalViewController:[imagePicker autorelease] animated:YES];
break;
}
default:
{
[self openEmailViewInViewController:self];
}
}
Ответ 4
У меня иногда возникает такая проблема.
Как это ни странно, после добавления NSLog перед ошибкой он работает
EDIT: В языках C вы не можете инициировать объекты в коммутаторе, если вы не ставите каждый "случай" между {} s
Ответ 5
Ну, это не правильный ответ, так как я не знаю, почему вы видите эту ошибку, но лучшим решением, чем переместить объявление за пределы блока switch, является создание явных областей видимости в отдельных случаях блока переключателя, Это обычно решает любую такую проблему с операторами switch, которые немного странны в том, что аргументы case обмениваются областью.
Итак:
switch (foo) {
case 0: {
// notice explicit scope here
break;
}
default: {
// here as well
}
}
Ответ 6
Я видел эту проблему раньше. Это связано с метками в C и относится к метке, используемой для gotos. Случай 1:, case2: строки - это метки. По какой-то причине первый оператор, следующий за меткой, не должен быть объявлением. Я сделаю некоторые исследования и обновления с дополнительной информацией, если кто-то другой не даст хорошего ответа.
Ответ 7
Хорошо, если я положил объявление переменной перед оператором switch, он отлично работает. Я предполагаю, что объявления переменных не являются выражениями в Objective C?