20

...在 ObjectiveC 中存在一些问题。

我基本上是在包装一个方法,并希望接受一个nil终止的列表并将同一个列表直接传递给我正在包装的方法。

这是我所拥有的,但它会导致EXC_BAD_ACCESS崩溃。检查本地变量,当它被传入时,它似乎otherButtonTitles只是一个NSStringotherButtonTitles:@"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终止列表?

4

3 回答 3

39

你不能这样做,至少不能以你想要的方式这样做。您想要做的(传递变量参数)需要有一个UIAlertView接受 a的初始化程序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]; \
}

但是,即使使用可变参数宏方法,每次您想要执行此操作时仍需要自定义宏。这不是一个非常可靠的选择。

于 2010-02-26T22:42:22.457 回答
0

如何构造一个NSInvocation对象?由于参数必须通过指针传递,因此您可以将指针传递给以 nil 结尾的列表。

您还可以使用自己迭代参数marg_list()并构建一个以零结尾的列表。

这些只是简单的建议;我还没有尝试过。

于 2010-02-26T22:34:14.737 回答
0

这特定于 OP 的UIAlertView-wrapping 案例,并且仅在 iOS7 上进行了测试:似乎一旦 aUIAlertView已用 初始化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 愉快地接受,解决方案是使用 otherButtonTitles (可以为 nil)otherButtons:nil进行初始化,并遍历可变参数,如上:UIAlertView

+ (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];
}
于 2013-10-29T09:50:33.493 回答