Objective-C, проходящий вокруг ... ноль завершенных списков аргументов - PullRequest
20 голосов
/ 27 февраля 2010

Возникли некоторые проблемы с ... в ObjectiveC.

Я в основном обертываю метод и хочу принять завершенный список 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 завершенный список?

Ответы [ 3 ]

40 голосов
/ 27 февраля 2010

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

Другой действительно грязный вариант - сделать его макросом с переменным числом аргументов. Вариационный макрос выглядит так:

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

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

0 голосов
/ 29 октября 2013

Это относится к случаю обтекания OP 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 с другимиButtonTitles (которые могут быть 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];

    // 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 голосов
/ 27 февраля 2010

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

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

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

...