Objective-C 传递... nil 终止的参数列表

发布于 2024-08-23 12:04:52 字数 996 浏览 6 评论 0原文

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 终止列表?

Having some issues with the ... in ObjectiveC.

I'm basically wrapping a method and want to accept a nil terminated list and directly pass that same list to the method I am wrapping.

Here's what I have but it causes an EXC_BAD_ACCESS crash. Inspecting the local vars, it appears when otherButtonTitles is simply a NSString when it is passed in with 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];
}

How do I simply siphon from the argument incoming to the argument outgoing, preserving the exact same nil terminated list?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

是你 2024-08-30 12:04:52

你不能这样做,至少不能以你想要的方式这样做。您想要做的事情(传递变量参数)需要在 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]; \
}

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

You can't do this, at least not in the way you're wanting to do it. What you want to do (pass on the variable arguments) requires having an initializer on UIAlertView that accepts a va_list. There isn't one. However, you can use the addButtonWithTitle: method:

+ (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];
}

This is, of course, very problem-specific. The real answer is "you can't implicitly pass on a variable argument list to a method/function that does not have a va_list parameter". You must therefore find a way around the problem. In the example you gave, you wanted to make an alertView with the titles you passed in. Fortunately for you, the UIAlertView class has a method that you can iteratively call to add buttons, and thereby achieve the same overall effect. If it did not have this method, you'd be out of luck.

The other really messy option would be to make it a variadic macro. A variadic macro looks like this:

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

However, even with the variadic macro approach, you'd still need a custom macro for each time you wanted to do this. It's not a very solid alternative.

晨光如昨 2024-08-30 12:04:52

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

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

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

How about constructing an NSInvocation object? Since arguments must be passed by pointer, you could pass the pointer to the nil-terminated list.

You could also iterate over the parameters using marg_list() and construct a nil-terminated list yourself.

These are just simple suggestions; I haven't tried them out.

初见 2024-08-30 12:04:52

这是特定于 OP 的 UIAlertView 包装情况,并且仅在 iOS7 上进行了测试:似乎一旦使用 otherButtons:nil 初始化了 UIAlertView >,然后将其样式设置为 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 (可以是 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];
}

This is specific to the OP's UIAlertView-wrapping case, and tested only on iOS7: It appears that once a UIAlertView has been initialised with otherButtons:nil, and then has its style set to UIAlertViewStylePlainTextInput it doesn't call its delegate's alertViewShouldEnableFirstOtherButton: to validate input. I'm not sure if this is a bug or intended behaviour but it broke my principle of least astonishment. This is reproducible with the following (I'll assume the delegate's alertViewShouldEnableFirstOtherButton: is implemented):

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

The solution, since UIAlertView happily accepts otherButtons:nil, is to initialise UIAlertView with otherButtonTitles (which can be nil), and iterate over the variadic arguments, as above:

+ (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];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文