Подтвердить что ты не робот

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

Имея некоторые проблемы с ... в ObjectiveC.

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

Вот что я имею, но это вызывает сбой EXC_BAD_ACCESS. Проверяя локальные вары, он появляется, когда otherButtonTitles является просто a 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 завершенный список?

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

Ответ 3

Это относится к случаю OP UIAlertView -wrapping и проверяется только на iOS7: Кажется, что после того, как a UIAlertView был инициализирован с помощью otherButtons:nil, а затем имеет свой стиль в UIAlertViewStylePlainTextInput, он не делает 't вызвать своего делегата 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];
}