2009-07-24 4 views
17

Ich habe diese switch-Anweisung in meinem Code:Weird-Schalter Fehler in 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]; 
} 

Und am UIImagePickerController Instanziierung in Fall 1 ich eine Störung erhalte:

error:expected expression before 'UIImagePickerController' 

und ich habe keine Ahnung, was ich falsch mache. Gedanken?

Oh, und buttonIndex ist ein NSInteger

Antwort

0

Nun, wenn ich die Variablendeklaration vor der Anweisung Schalter setzen es funktioniert gut. Ich denke, Variablendeklarationen sind keine Ausdrücke in Objective C?

2

Gut, das ist keine richtige Antwort, wie ich weiß nicht, warum Sie diesen Fehler zu sehen, aber eine bessere Lösung als die Deklaration außerhalb des Schalterblock zu bewegen ist, um explizite Bereiche innerhalb der machen Einzelfälle des Schalterblocks. Das löst normalerweise ein solches Problem mit switch-Anweisungen, die insofern etwas seltsam sind, als die case-Anweisungen den Bereich teilen.

So:

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

ich vor diesem Problem gesehen habe. Es hat mit den Labels in C zu tun, und würde auch für ein Label gelten, das für Gotos verwendet wird. Case1 :, Case2: Zeilen sind Labels. Aus welchem ​​Grund auch immer, die erste Aussage nach einem Label darf keine Deklaration sein. Ich werde etwas recherchieren und mit mehr Informationen aktualisieren, wenn jemand anderes keine gute Antwort gibt.

5

Eine Sache, die ich in dieser Situation tun möchte, ist den Inhalt jeder case in Klammern setzen. Dies wird vom Compiler erlaubt:

+1

Hinweis: In C können Sie zusätzliche Klammern fast überall platzieren, solange die korrekte Verschachtelung beibehalten wird. if (foo) {{{{}}}}} // ist vollkommen legal – Amagrammer

+0

Danke für Ihre Antwort, diese Art von Einfachheit macht diese Seite so nützlich! Mach weiter. –

62

Ich lief auf dieses Problem ein, und eines Tages entschied ich mich dazu zu graben.

Die kurze Nicht-Antwort, aber pragmatische Lösung:

Ein Weg, um dieses „Problem“ zu arbeiten, ist ein Semikolon zu verwenden, ;, direkt nach dem Doppelpunkt einer case ...: Aussage. Zum Beispiel mit dem Beispiel, das Sie zur Verfügung gestellt, kann es „fixiert“ werden, so kompiliert und verhält sich wie Sie intuitiv es erwarten würde:

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

Die lange Antwort:

Einige Geschichte: Früher C nur erlaubte es Ihnen, zu Beginn eines Blocks "block local" Variablen zu deklarieren, denen dann verschiedene Anweisungen folgten. C99 hat Dinge geändert, so dass Sie variable Deklarationen und Anweisungen frei mischen können.

Im Kontext der C99 BNF-Grammatik ist eine Variablendeklaration eine und eine Anweisung ist eine statement. A statement bedeutet mehrere Dinge, von denen einer als compound-statement bekannt ist, der der bekannte { ... } Block ist.Der ... Teil ist lose definiert als zero or moreblock-items mit block-item lose als either adeclarationor astatement definiert ist.

Das Problem liegt in der Art und Weise ein labeled-statement (a goto Etikett, case label oder default: im wesentlichen die ...: Anweisungen) definiert ist, die lose ...: zero or morestatements definiert ist. Es ist nicht, wie man intuitiv erwarten könnte, zero or morestatementsordeclarations. Die Verwendung eines ; direkt nach dem labeled-statement s : beendet im Wesentlichen den zero or morestatements Teil eines labeled-statement. Dies führt dazu, dass die Grammatik auf die compound-statement Definition zurückfällt, was ermöglicht, dass die nächste "Anweisung" entweder eine statement oder ist.

Ich habe nicht untersucht, ob dies ein unbeabsichtigtes Übersehen der C99-Sprachspezifikation ist (in der Praxis ein Fehler im C99-Standard), oder ob dies eine pragmatische Zugeständnis an die Komplexität des Schreibens von Grammatiken ist . Wenn Sie mit dem Schreiben von Grammatiken nicht vertraut sind, werden Sie feststellen, dass die obige Erklärung eine Rekursion ermöglicht: A labeled-statement kann case 1: case 2: case 3: entsprechen. Zu vereinfachende Begriffe (1), einige Arten von Grammatik Rekursion sind einfach und "unzweideutig", während andere komplex und "mehrdeutig" sind. Der Einfachheit halber behandeln die meisten Sprachwerkzeuge nur den Fall, bei dem eine Mehrdeutigkeit deterministisch gelöst werden muss, indem man sich nichts anderes als "das nächste Token" ansieht. Ich erwähne das nur deshalb, weil dies zwar intuitiv als ein Mangel in der C99-Spezifikation erscheint, es aber zwingende, nicht offensichtliche Gründe dafür gibt ... und ich habe mir keine Mühe gegeben, weitere Untersuchungen zu diesem Thema durchzuführen, um das herauszufinden in jedem Fall.

(1) Dies ist keine technisch genaue Beschreibung, aber eine angemessene Annäherung für diejenigen, die nicht mit den damit verbundenen Problemen vertraut sind.

EDIT:

Die Lösung, die ich Werke gab in „die meisten“ Fällen (Fälle „Nutzungen“ zu sein, nicht switchcase s), aber es ist in einem Fall fehlschlagen: Das wird nicht funktionieren, wenn die Deklaration deklariert ein C99 variable length array, wie case 1:; void *ptrs[count]; Dies liegt daran, in C99 ist es ein Fehler zu "überspringen" die Deklaration eines C99 VLA, die in demselben lexikalischen Bereich ist, in dem der Sprung stattfand. In diesen Fällen müssen Sie case 1: { void *ptrs[count]; } verwenden. In diesem Fall endet der Umfang des VLA ptrs bei der Schlussmelde }. Das ist komplizierter, als es zuerst erscheint, da die folgende vollkommen legal C-Code ist, obwohl auf den ersten Blick würde man intuitiv denken, es ist nicht:

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

Dies kompiliert, und wenn ausführen, druckt case 3.

Siehe auch: manchmal Wikipedia: Duffs Device

+0

Nun, es ist viel mehr als ich zuvor wusste. Ich wusste nur, dass C aus irgendeinem Grund einen Teilbereich benötigte, wenn Sie eine Erklärung in einen Fall schreiben wollten. Vielen Dank. – Amagrammer

+1

Verdammt, das ist eine gute Antwort. –

+4
3

ich diese Art von Problem.

Wie seltsam es auch scheinen mag, nachdem ich ein NSLog vor dem Fehler hinzufügen, funktioniert es

EDIT: In C Sprachen können Sie nicht Instanciate Objekte in einem Schalter, wenn Sie alle nicht „Fall setzen "zwischen {} s