2010-02-26 2 views
20

Имея некоторые проблемы с ... в ObjectiveC.Objective-C, проходящий вокруг ... nil завершенных списков аргументов

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

Вот что у меня есть, но это приводит к аварии EXC_BAD_ACCESS. Осмотр местного ВАРА, он появляется, когда otherButtonTitles просто NSString, когда он проходит через 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]; 
} 

Как просто сифон от аргумента входящего аргументу исходящего, сохраняя тот же nil прекращен список?

+1

Первый объект в списке VARIADIC метод не является частью самого va_list, поэтому вы видите otherButtonTitles как в NSString. То есть, va_list содержит только объекты в разделе «...». – Don

+1

Поскольку Objective-C является надмножеством C, ср. http://stackoverflow.com/questions/150543/forward-an-invocation-of-a-variadic-function-in-c. – Don

ответ

40

Вы не можете этого сделать, по крайней мере, не так, как вы этого хотите. То, что вы хотите сделать (передать переменные аргументы), требует наличия инициализатора на UIAlertView, который принимает va_list. Нет. Тем не менее, вы можете использовать метод 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]; 
} 

Это, конечно, очень конкретных проблем. Реальный ответ: «вы не можете неявно передавать список переменных аргументов методу/функции, который не имеет параметра va_list». Поэтому вы должны найти способ решения проблемы. В примере, который вы указали, вы хотели сделать alertView с заголовками, которые вы передали. К счастью для вас, класс UIAlertView имеет метод, который вы можете итеративно вызывать для добавления кнопок и тем самым достичь того же общего эффекта. Если бы у него не было этого метода, вам не повезло.

Другим действительно грязным вариантом было бы сделать его вариационным макросом. VARIADIC макрос выглядит следующим образом:

#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]; \ 
} 

Однако, даже с VARIADIC макроподхода, вы все еще нужен пользовательский макрос для каждого времени вы хотели, чтобы сделать это. Это не очень надежная альтернатива.

+1

Прохладный подход, но я надеялся использовать эту технику в других местах, где такой метод может не существовать, чтобы помочь в списке аргументов. На самом деле нет возможности динамически создавать список с завершенным нулем? –

+0

@Squeegy вы можете подделать 'va_list' (см. Ссылку cocoawithlove в комментарии @ Don), но если метод, который вы хотите вызвать, принимает' va_list' (в отличие от '...'), вы не можете использовать Это. –

+0

К счастью, решение Dave работает для вашей конкретной ситуации. – Don

0

Как насчет строительства объекта NSInvocation? Поскольку аргументы должны быть переданы указателем, вы можете передать указатель на список, завершенный нулем.

Вы также можете выполнить итерацию по параметрам с помощью marg_list() и самостоятельно составить список нулевого конца.

Это простые предложения; Я их не пробовал.

+0

«' NSInvocation' не поддерживает вызовы методов с переменными числами аргументов или аргументами 'union'. - http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSInvocation_Class/Reference/Reference.html#//apple_ref/doc/uid/20000212-1804 –

+0

Ну, это убивает предложение! – Don

+0

Я думаю, что я могу что-то подобное перебирать по списку: http://en.wikipedia.org/wiki/Variadic_function#Variadic_functions_in_C.2C_Objective-C.2C_C.2B.2B.2C_and_D, но как я могу использовать 'marg_list() 'для генерации одного динамически я могу вернуться обратно. –

0

Это относится только к UIAlertView -ОКУТЫВАЮЩЕМУ делу ФПА, и тестировался только на iOS7: Похоже, что, как только UIAlertView инициализировано с otherButtons:nil, а затем установить его стиль UIAlertViewStylePlainTextInput он не называет его делегат alertViewShouldEnableFirstOtherButton: в подтвердите ввод. Я не уверен, что это ошибка или намеренное поведение, но это сломало мой принцип наименьшего удивления.Это воспроизводимое следующее (я предполагаю, что реализуется делегат alertViewShouldEnableFirstOtherButton:):

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

раствором, так как UIAlertView радостно принимает otherButtons:nil, это инициализирует UIAlertView с otherButtonTitles (который может быть нулевым), и перебирать то VARIADIC аргументы, как указано выше:

+ (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

Хотя это интересная информация, и ее обязательно следует сообщать в Apple [репортер ошибок] (http://bugreport.apple.com/), это не ответ на этот пост. Насколько я понимаю, он не предоставляет дополнительную информацию к заданному вопросу. –

+0

Уже сообщалось. Я согласен, частично; это исправление принятого ответа в том месте, куда Google привел меня, когда я боролся с переориентированной оболочкой UIAlertView. Может быть, это поможет кому-то еще ... –