2009-07-24 26 views
17

Tôi có câu lệnh switch này trong mã của tôi:Weird Chuyển lỗi trong 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]; 
} 

Và tại instantiation UIImagePickerController trong Trường hợp 1 Tôi nhận được một lỗi:

error:expected expression before 'UIImagePickerController' 

và tôi có không biết tôi đang làm gì sai. Suy nghĩ?

Oh, và buttonIndex là một NSInteger

Trả lời

0

Vâng, nếu tôi đặt việc khai báo biến trước khi câu lệnh switch nó hoạt động tốt. Tôi đoán khai báo biến không phải là 'biểu thức' trong Mục tiêu C?

2

Vâng đây không phải là một câu trả lời thích hợp, như tôi không biết tại sao bạn thấy lỗi đó, nhưng một giải pháp tốt hơn để di chuyển tờ khai bên ngoài các khối chuyển đổi là để làm cho phạm vi rõ ràng trong các trường hợp riêng lẻ của khối chuyển đổi. Điều đó thường giải quyết mọi vấn đề như vậy với các câu lệnh switch, điều này hơi lạ trong trường hợp chia sẻ câu lệnh case.

Vì vậy:

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

Tôi đã nhìn thấy vấn đề này trước. Nó phải làm với các nhãn trong C, và sẽ áp dụng cho một nhãn được sử dụng cho gotos là tốt. Trường hợp1 :, case2: dòng là nhãn. Vì bất kỳ lý do gì, tuyên bố đầu tiên sau một nhãn không phải là một tuyên bố. Tôi sẽ làm một số nghiên cứu và cập nhật với nhiều thông tin hơn nếu người khác không đưa ra câu trả lời hay.

5

Một điều tôi muốn làm trong trường hợp này là đặt nội dung của mỗi case vào trong niềng răng. Điều này được phép bởi trình biên dịch:

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

Lưu ý: Trong C, bạn có thể đặt thêm niềng răng chỉ là về bất cứ nơi nào, miễn là làm tổ thích hợp được bảo tồn. if (foo) {{{{{}}}}} // hoàn toàn hợp pháp – Amagrammer

+0

Cảm ơn câu trả lời của bạn, loại đơn giản này làm cho trang web này trở nên hữu ích! Giữ nó lên. –

62

Tôi gặp phải vấn đề này, và một ngày tôi quyết định đào sâu vào nó.

Ngắn phi câu trả lời nhưng giải pháp thực dụng:

Một cách để làm việc xung quanh "vấn đề" này là sử dụng một dấu chấm phẩy, ;, ngay sau dấu hai chấm của một tuyên bố case ...:. Ví dụ, sử dụng ví dụ mà bạn cung cấp, nó có thể được "cố định" vì vậy nó biên dịch và hoạt động như bạn sẽ trực giác mong đợi nó:

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

Câu trả lời dài:

Một số lịch sử: Trước đây, C chỉ cho phép bạn khai báo các biến "khối cục bộ" ở đầu khối, sau đó được theo sau bởi các câu lệnh khác nhau. C99 đã thay đổi mọi thứ để bạn có thể tự do trộn lẫn các khai báo và khai báo biến.

Trong ngữ cảnh ngữ pháp BNF C99, khai báo biến là declaration và tuyên bố là statement. A statement có nghĩa là nhiều thứ, một trong số đó được gọi là compound-statement, là khối { ... } quen thuộc.Phần ... là lỏng lẻo định nghĩa là zero or moreblock-items với block-item được định nghĩa lỏng lẻo như either adeclarationor astatement.

Vấn đề nằm trong cách một labeled-statement (một nhãn goto, trường hợp nhãn, hoặc default:, về cơ bản các ...: báo cáo) được định nghĩa, đó là lỏng lẻo định nghĩa ...: zero or morestatements. Nó không phải là, như một trực giác có thể mong đợi, zero or morestatementsordeclarations. Việc sử dụng một số ; ngay sau khi labeled-statement s : về cơ bản sẽ chấm dứt phần zero or morestatements một phần của labeled-statement. Điều này khiến ngữ pháp quay trở lại định nghĩa compound-statement, cho phép "tuyên bố" tiếp theo là statement hoặc declaration.

Tôi chưa khảo sát xem đây có phải là sự vô tình vượt qua thông số ngôn ngữ C99 (trong điều kiện thực tế, lỗi trong tiêu chuẩn C99) hay là sự nhượng bộ thực tế đối với sự phức tạp trong việc viết ngữ pháp ngôn ngữ . Nếu bạn không quen với việc viết các ngữ pháp, bạn sẽ nhận thấy rằng lời giải thích ở trên cho phép đệ quy: A labeled-statement có thể khớp với case 1: case 2: case 3:. Trong các điều khoản quá đơn giản (1), một số loại đệ quy ngữ pháp rất đơn giản và "không rõ ràng", trong khi các loại khác phức tạp và "mơ hồ". Để đơn giản, hầu hết các công cụ ngôn ngữ sẽ chỉ xử lý trường hợp bất kỳ sự mơ hồ nào phải được giải quyết một cách xác định bằng cách xem không có gì hơn "mã thông báo tiếp theo". Tôi đề cập đến điều này chỉ vì trong khi điều này có vẻ trực giác giống như thiếu thông số C99, có thể có lý do thuyết phục, không rõ ràng tại sao điều này tồn tại ... và tôi không bận tâm nghiên cứu thêm về chủ đề này để tìm hiểu một trong hai cách.

(1) Đây không phải là mô tả chính xác về mặt kỹ thuật, nhưng gần đúng cho những người không quen với các vấn đề liên quan.

EDIT:

Các giải pháp tôi đưa công trình vào "hầu hết" các trường hợp (trường hợp là "tập quán", không switchcase s), nhưng nó thất bại trong một trường hợp: Điều này sẽ không hoạt động khi khai báo tuyên bố một C99 variable length array, chẳng hạn như case 1:; void *ptrs[count]; Điều này là do trong C99 nó là một lỗi để "nhảy qua" tuyên bố của một VLA C99 đó là trong phạm vi từ vựng tương tự, nơi nhảy đã diễn ra. Trong những trường hợp này, bạn cần sử dụng case 1: { void *ptrs[count]; }. Trong trường hợp này, phạm vi của ptrs VLA sẽ kết thúc vào lúc đóng }. Đây là phức tạp hơn nó đầu tiên xuất hiện vì sau đây là mã C hoàn toàn hợp pháp, mặc dù thoạt nhìn ai bằng trực giác nghĩ rằng nó không phải là:

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

này biên dịch, và khi chạy, bản in case 3.

Xem thêm: Wikipedia: Duffs Device

+0

Vâng, nó còn nhiều hơn * tôi * đã biết trước đây. Tôi chỉ biết rằng vì một lý do nào đó C yêu cầu một phạm vi phụ nếu bạn muốn đặt một tuyên bố trong một trường hợp. Cảm ơn. – Amagrammer

+1

Chết tiệt, đó là một câu trả lời hay. –

+4
3

Tôi gặp vấn đề này đôi khi.

Như lạ như nó có vẻ, sau khi tôi thêm một NSLog trước khi lỗi, nó hoạt động

EDIT: Trong ngôn ngữ C bạn có thể không phải đối tượng instanciate trong một chuyển đổi nếu bạn không đặt tất cả các "trường hợp "between {} s