2010-02-26 36 views
20

Có một số vấn đề với ... trong Mục tiêuC.Mục tiêu-C đi qua ... không có danh sách đối số được kết thúc

Tôi về cơ bản là gói một phương thức và muốn chấp nhận danh sách chấm dứt nil và chuyển trực tiếp danh sách đó vào phương pháp tôi đang gói.

Đây là những gì tôi có nhưng gây ra sự cố EXC_BAD_ACCESS. Kiểm tra việc vars địa phương, nó xuất hiện khi otherButtonTitles chỉ đơn giản là một NSString khi nó được thông qua với otherButtonTitles:@"Foo", nil]

+ (void)showWithTitle:(NSString *)title 
       message:(NSString *)message 
      delegate:(id)delegate 
    cancelButtonTitle:(NSString *)cancelButtonTitle 
    otherButtonTitles:(NSString *)otherButtonTitles, ... 
{ 
    UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title 
                message:message 
                delegate:delegate 
              cancelButtonTitle:cancelButtonTitle 
              otherButtonTitles:otherButtonTitles] autorelease]; 
    [alert show]; 
} 

Làm thế nào để đơn giản siphon từ lý luận đến để tranh luận đi, bảo tồn chính xác cùng nil danh sách chấm dứt?

+1

Đối tượng đầu tiên trong danh sách phương thức variadic không phải là một phần của chính va_list, đó là lý do tại sao bạn thấy các phụ đềButton khác là một NSString. Tức là, va_list chỉ bao gồm các đối tượng trong phần "...". – Don

+1

Vì mục tiêu-C là một siêu của C, cf. http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c. – Don

Trả lời

40

Bạn không thể làm điều này, ít nhất không theo cách bạn muốn thực hiện. Những gì bạn muốn làm (thông qua các đối số biến) yêu cầu phải có một initializer trên UIAlertView chấp nhận một va_list. Không có một. Tuy nhiên, bạn có thể sử dụng phương pháp addButtonWithTitle::

+ (void)showWithTitle:(NSString *)title 
       message:(NSString *)message 
      delegate:(id)delegate 
    cancelButtonTitle:(NSString *)cancelButtonTitle 
    otherButtonTitles:(NSString *)otherButtonTitles, ... 
{ 
    UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title 
                message:message 
                delegate:delegate 
              cancelButtonTitle:cancelButtonTitle 
              otherButtonTitles:nil] autorelease]; 
    if (otherButtonTitles != nil) { 
     [alert addButtonWithTitle:otherButtonTitles]; 
     va_list args; 
     va_start(args, otherButtonTitles); 
     NSString * title = nil; 
     while(title = va_arg(args,NSString*)) { 
      [alert addButtonWithTitle:title]; 
     } 
     va_end(args); 
    } 

    [alert show]; 
} 

Điều này, tất nhiên, rất cụ thể về vấn đề. Câu trả lời thực sự là "bạn không thể chuyển hoàn toàn vào danh sách đối số biến cho phương thức/hàm không có thông số va_list". Do đó, bạn phải tìm cách giải quyết vấn đề. Trong ví dụ bạn đã đưa ra, bạn muốn tạo một alertView với các tiêu đề mà bạn truyền vào. May mắn cho bạn, lớp UIAlertView có một phương thức mà bạn có thể lặp lại gọi để thêm các nút và do đó đạt được hiệu quả tổng thể tương tự. Nếu nó không có phương pháp này, bạn sẽ không may mắn.

Tùy chọn thực sự lộn xộn khác sẽ là biến nó thành macro Vĩ mô. Macro Vĩ mô có dạng như sau:

#define SHOW_ALERT(title,msg,del,cancel,other,...) { \ 
    UIAlertView *_alert = [[[UIAlertView alloc] initWithTitle:title message:msg delegate:del cancelButtonTitle:cancel otherButtonTitles:other, ##__VA_ARGS__] autorelease]; \ 
    [_alert show]; \ 
} 

Tuy nhiên, ngay cả với phương pháp macro Vĩ mô, bạn vẫn cần macro tùy chỉnh cho mỗi lần bạn muốn thực hiện việc này. Nó không phải là một thay thế rất vững chắc.

+1

Một cách tiếp cận thú vị, nhưng tôi đã hy vọng sử dụng kỹ thuật này ở những nơi khác mà một phương pháp như thế này có thể không tồn tại để giúp đỡ với danh sách đối số. Thực sự không có cách nào để tạo một danh sách kết thúc tự động không? –

+0

@Squeegy bạn có thể giả mạo một 'va_list' (xem liên kết cocoawithlove trong bình luận của @ Don), nhưng trừ khi bạn muốn gọi phương thức' va_list' (trái với '...'), bạn không thể sử dụng nó. –

+0

May mắn thay, giải pháp của Dave phù hợp với hoàn cảnh cụ thể của bạn. – Don

0

Làm thế nào về việc xây dựng một đối tượng NSInvocation? Vì các đối số phải được truyền qua con trỏ, bạn có thể chuyển con trỏ tới danh sách không được kết thúc.

Bạn cũng có thể lặp qua các tham số bằng cách sử dụng marg_list() và tự xây dựng danh sách không được kết thúc bằng nil.

Đây chỉ là những gợi ý đơn giản; Tôi đã không thử chúng.

+0

"' NSInvocation' không hỗ trợ các lời gọi của các phương thức với một số biến số của đối số hoặc đối số 'union'." - http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html#//apple_ref/doc/uid/20000212-1804 –

+0

Vâng, điều đó sẽ giết chết gợi ý! – Don

+0

Tôi nghĩ rằng tôi có thể một cái gì đó như thế này để lặp qua danh sách: http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.2C_Objective-C.2C_C.2B.2B.2C_and_D nhưng làm cách nào để sử dụng 'marg_list() 'để tạo ra một động lực tôi có thể đường ống trở lại. –

0

này là cụ thể cho UIAlertView trường hợp -wrapping của OP, và chỉ được thử nghiệm trên iOS7: Có vẻ như một lần UIAlertView đã được khởi tạo với otherButtons:nil, và sau đó đã phong cách của nó thiết lập để UIAlertViewStylePlainTextInput nó không gọi đại biểu của nó của alertViewShouldEnableFirstOtherButton: để xác thực đầu vào. Tôi không chắc đây có phải là lỗi hay hành vi dự định nhưng nó đã phá vỡ nguyên tắc của tôi về sự kinh ngạc nhất.Đây là tái sản xuất như sau (tôi sẽ giả định của alertViewShouldEnableFirstOtherButton: đại biểu được thực hiện):

UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"Title" 
              message:@"message" 
              delegate:self   
            cancelButtonTitle:@"Cancel" 
            otherButtonTitles:nil]; 
[av setAlertViewStyle:UIAlertViewStylePlainTextInput]; 
[av addButtonWithTitle:@"OK"]; 
[av show]; 

Các giải pháp, vì UIAlertView vui vẻ chấp nhận otherButtons:nil, là để khởi UIAlertView với otherButtonTitles (có thể bằng không), và duyệt qua đối số variadic, như trên:

+ (void)showWithTitle:(NSString *)title 
       message:(NSString *)message 
      delegate:(id)delegate 
    cancelButtonTitle:(NSString *)cancelButtonTitle 
    otherButtonTitles:(NSString *)otherButtonTitles, ... 
{ 
    UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:title 
                message:message 
                delegate:delegate 
              cancelButtonTitle:cancelButtonTitle 
              otherButtonTitles:otherButtonTitles] autorelease]; 

    // add your [alert setAlertViewStyle:UIAlertViewStylePlainTextInput] etc. as required here 

    if (otherButtonTitles != nil) { 
     va_list args; 
     va_start(args, otherButtonTitles); 
     NSString * title = nil; 
     while(title = va_arg(args,NSString*)) { 
      [alert addButtonWithTitle:title]; 
     } 
     va_end(args); 
    } 

    [alert show]; 
} 
+0

Mặc dù đây là thông tin thú vị và chắc chắn phải được báo cáo tại [phóng viên lỗi] của Apple (http://bugreport.apple.com/), đây không phải là câu trả lời cho bài đăng này. Khi tôi hiểu nó, nó không cung cấp thêm thông tin cho câu hỏi được hỏi. –

+0

Đã được báo cáo. Tôi đồng ý, một phần; đó là một sự điều chỉnh cho câu trả lời được chấp nhận ở nơi Google đưa tôi đến khi tôi đang phải vật lộn với gói sản phẩm VARIA UIAlertView của riêng tôi. Có lẽ nó sẽ giúp người khác ... –

Các vấn đề liên quan