2009-07-24 15 views
17

tengo esta sentencia switch en mi código:de error Interruptor extraño en 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]; 
} 

Y en la creación de instancias UIImagePickerController en el Caso 1 Recibo un error:

error:expected expression before 'UIImagePickerController' 

y tengo no tengo idea de lo que estoy haciendo mal. ¿Pensamientos?

Ah, y buttonIndex es un NSInteger

Respuesta

0

Bueno, si pongo la declaración de variables antes de la sentencia switch que funciona bien. ¿Supongo que las declaraciones variables no son 'expresiones' en Objective C?

2

Bueno, esto no es una respuesta adecuada, ya que no sé por qué se ve que el error, pero una solución mejor que para mover la declaración fuera del bloque de conmutación es hacer explícitas alcances dentro de la casos individuales del bloque interruptor. Eso generalmente resuelve cualquier problema de este tipo con las sentencias switch, que son un poco raras porque las sentencias case comparten el alcance.

Así:

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

que he visto este problema antes. Tiene que ver con las etiquetas en C, y se aplicaría a una etiqueta usada también para gotos. Case1 :, case2: las líneas son etiquetas. Por alguna razón, la primera declaración que sigue a una etiqueta no debe ser una declaración. Investigaré y actualizaré con más información si alguien más no da una buena respuesta.

5

Una cosa que me gusta hacer en esta situación es poner el contenido de cada case entre llaves. Esto está permitido por el compilador:

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

Nota: En C, puede colocar llaves adicionales en cualquier lugar, siempre que se conserve la anidación adecuada. if (foo) {{{{{}}}}} // es perfectamente legal – Amagrammer

+0

¡Gracias por su respuesta, este tipo de simplicidad hace que este sitio sea tan útil! Seguid así. –

62

que corrieron a este problema, y ​​un día decidió que se hundía en ella.

El corto no respuesta pero solución pragmática:

Una manera de evitar este "problema" es utilizar un punto y coma, ;, justo después de los dos puntos de una declaración case ...:. Por ejemplo, utilizando el ejemplo que nos ha facilitado, puede ser "fijo", por lo que se compila y se comporta como lo haría intuitivamente esperar que:

case 1:; // <- Note semi-colon. 
      UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init]; 
      imagePicker.delegate = self; 

La respuesta larga:

Un poco de historia: Anteriormente, C sólo le permitió declarar las variables "bloquear local" al comienzo de un bloque, que fue seguido por varias declaraciones. C99 cambió las cosas para que pudieras mezclar libremente las declaraciones y declaraciones de variables.

En el contexto de la gramática C99 BNF, una declaración de variable es declaration, y una instrucción es statement. Un statement significa varias cosas, una de ellas se conoce como compound-statement, que es el familiar bloque { ... }.La parte ... se define en términos generales como zero or moreblock-items, con un block-item ser vagamente definido como either adeclarationor astatement.

El problema radica en la forma en que un labeled-statement (una etiqueta Goto, etiqueta de la caja, o default:, esencialmente los ...: declaraciones) se define, que es vagamente definido ...: zero or morestatements. No es, como se podría esperar intuitivamente, zero or morestatementsordeclarations. El uso de un ; justo después de labeled-statement s : esencialmente termina el zero or morestatements parte de un labeled-statement. Esto hace que la gramática vuelva a la definición compound-statement, que permite que la siguiente "declaración" sea statement o declaration.

No he investigado si esta es una visión involuntaria del lenguaje C99 (en términos prácticos, un error en el estándar C99), o si esta es una concesión pragmática a las complejidades de escribir gramáticas del lenguaje . Si no está familiarizado con la escritura de gramáticas, notará que la explicación anterior permite la recursión: A labeled-statement puede coincidir con case 1: case 2: case 3:. En términos excesivamente simplistas (1), algunos tipos de recursión gramatical son simples e "inequívocos", mientras que otros son complejos y "ambiguos". Para simplificar, la mayoría de las herramientas de lenguaje solo manejarán el caso en el que cualquier ambigüedad debe resolverse determinísticamente mirando nada más que "el siguiente token". Menciono esto solo porque si bien esto podría parecer intuitivamente como una deficiencia en la especificación C99, puede haber razones convincentes y no obvias por las que esto existe ... y no me he molestado en investigar más sobre el tema para averiguarlo. de cualquier manera.

(1) Esto no pretende ser una descripción técnicamente precisa, sino una aproximación razonable para aquellos que no están familiarizados con los problemas involucrados.

EDIT:

La solución que dio obras en la "mayoría" de los casos (casos son "usos", no switchcase s), pero no fallar en un caso: Esto no funcionará cuando el declaración declara un C99 variable length array, como case 1:; void *ptrs[count]; Esto se debe a que en C99 es un error "saltar" la declaración de un C99 VLA que está en el mismo alcance léxico donde tuvo lugar el salto. En estos casos, debe usar case 1: { void *ptrs[count]; }. En este caso, el alcance del ptrs VLA finaliza en el cierre }. Esto es más complicado de lo que parece ya que el siguiente es el código C perfectamente legal, aunque a primera vista se podría pensar intuitivamente que no es:

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"); 
    } 
} 

Esto compila, y cuando se ejecuta, impresiones case 3.

Ver también: Wikipedia: Duffs Device

+0

Bueno, es mucho más que * I * sabía antes. Solo sabía que, por algún motivo, C requería un subámbito si quería poner una declaración dentro de un caso. Gracias. – Amagrammer

+1

Maldita sea, esa es una buena respuesta. –

+4
3

tengo este tipo de problema a veces.

Por extraño que pueda parecer, después agrego un NSLog antes del error, funciona

EDIT: caso En lenguajes C no se puede objetos instanciate en un interruptor si no poner todos" "entre {} s