Objective-C passing around … nil terminated argument lists

后端 未结 3 1797
情书的邮戳
情书的邮戳 2020-11-30 03:18

Having some issues with the ... in ObjectiveC.

I\'m basically wrapping a method and want to accept a nil terminated list and directly pass

相关标签:
3条回答
  • 2020-11-30 03:46

    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.

    0 讨论(0)
  • 2020-11-30 04:04

    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.

    0 讨论(0)
  • 2020-11-30 04:05

    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];
    }
    
    0 讨论(0)
提交回复
热议问题