2009-07-24 2 views
17

У меня есть этот переключатель заявление в моем коде:Weird ошибка Переключение в Obj-C

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' 

и у меня есть не знаю, что я делаю неправильно. Мысли?

О, и buttonIndex является NSInteger

ответ

0

Ну, если я ставлю объявление переменной перед оператором коммутатора он работает нормально. Я предполагаю, что объявления переменных не являются выражениями в Objective C?

2

Ну это не правильный ответ, так как я не знаю, почему вы видите эту ошибку, но лучшее решение, чем переместить декларацию за пределы блока переключателей, чтобы сделать четкие областей в пределах отдельные случаи блока переключения. Обычно это решает любую проблему с операторами switch, которые немного странны в том, что аргументы в отношении аргументов case обмениваются.

Итак:

switch (foo) { 
    case 0: { 
     // notice explicit scope here 
     break; 
    } 
    default: { 
     // here as well 
    } 
} 
1

Я видел этот вопрос раньше. Это связано с метками в C и относится к метке, используемой для gotos. Случай 1 :, case2: строки - это метки. По какой-то причине первый оператор, следующий за меткой, не должен быть объявлением. Я сделаю некоторые исследования и обновления с дополнительной информацией, если кто-то другой не даст хороший ответ.

5

Одна вещь, которую я хотел бы сделать в этой ситуации, - это разместить содержимое каждого 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]; 
    } 
} 
+1

Примечание: в C вы можете поместить дополнительные фигурные скобки практически в любом месте, если сохраняется правильное вложение. if (foo) {{{{{}}}}} // совершенно законно – Amagrammer

+0

Спасибо за ваш ответ, этот тип простоты делает этот сайт настолько полезным! Так держать. –

62

Я столкнулся с этой проблемой, и однажды я решил в нее залезть.

Короткий без ответа, но прагматичное решение:

Способ обойти эту «проблему» заключается в использовании запятой, ;, сразу после ободочной кишки в 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 moreblock-items, с block-item определяется, как свободно either adeclarationor astatement.

Проблема заключается в том, как labeled-statement (метка Гото, случай, этикетки или default:, по существу те ...: высказывания) определяется, которая свободно определяется ...: zero or morestatements. Это не так, как можно было бы ожидать, интуитивно, zero or morestatementsordeclarations. Использование ; сразу после labeled-statement с : по существу заканчивает zero or morestatements часть labeled-statement. Это приводит к тому, что грамматика возвращается к определению compound-statement, которое позволяет следующему «заявлению» быть либо statement, либо declaration.

Я не исследовал, является ли это непреднамеренным просмотром спецификации языка C99 (на практике, ошибка в стандарте C99), или если это прагматическая уступка сложностям написания языковых грамматик , Если вы не знакомы с написанием грамматик, вы заметите, что приведенное выше объяснение допускает рекурсию: A labeled-statement может соответствовать case 1: case 2: case 3:. В чрезмерно упрощенных терминах (1), некоторые типы рекурсии грамматики просты и «однозначны», а другие сложны и «неоднозначны». Для простоты большинство языковых инструментов будут обрабатывать только случай, когда любая двусмысленность должна быть детерминистически решена, рассматривая не что иное, как «следующий токен». Я упоминаю об этом только потому, что, хотя это может показаться интуитивно недостаточным в спецификации C99, могут быть убедительные, неочевидные причины, почему это существует ... и я не потрудился провести дальнейшие исследования по этому вопросу, чтобы узнать так или иначе.

(1) Это не должно быть технически точным описанием, но разумным приближением для тех, кто не знаком с затронутыми проблемами.

EDIT:

Решение, которое я дал работы в «большинстве» случаев (дел, «обычаи», не switchcase с), но это не обязательно в одном случае: Это не будет работать, если Объявление объявляет C99 variable length array, например case 1:; void *ptrs[count]; Это связано с тем, что в C99 ошибка «проскользнуть» после объявления VLA C99, которая находится в той же лексической области, где произошел скачок. В этих случаях вам необходимо использовать case 1: { void *ptrs[count]; }. В этом случае объем VLA ptrs заканчивается на закрытии }. Это гораздо сложнее, чем кажется на первый взгляд, так как следующий совершенно законна код 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.

Смотрите также: Wikipedia: Duffs Device

+0

Ну, это намного больше, чем я знал раньше. Я просто знал, что по какой-то причине C требуется подзадача, если вы хотите разместить декларацию внутри футляра. Благодарю. – Amagrammer

+1

Черт, это хороший ответ. –

+4

<начинает медленно хлопать> – griotspeak

3

У меня есть такая проблема иногда.

Как бы странно это может показаться, после того, как я добавляю NSLog перед ошибкой, она работает

EDIT: В C языках вы не можете создании экземпляра объектов в коммутаторе, если вы не ставите каждый «случай "между {} s

 Смежные вопросы

  • Нет связанных вопросов^_^