Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I sent an array of strings into an UIActionSheet varargs init method?

I have an action sheet with options that vary depending on the circumstances. There are enough different button titles that I would like to construct an array of those button titles first, but I can't figure out how to convert that into the varargs format.

I want to do something like this:

NSMutableArray *buttonTitles = [NSMutableArray array];
if (condition1) {
    [buttonTitles addObject: @"Do action 1"];
}
if (condition2) {
    [buttonTitles addObject: @"Do action 2"];
}
if (condition3) {
    [buttonTitles addObject: @"Do action 3"];
}
if (condition4) {
    [buttonTitles addObject: @"Do action 4"];
}
UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle: nil delegate: self cancelButtonTitle: @"Cancel" destructiveButtonTitle: nil otherButtonTitles: buttonTitles] autorelease];

Now obviously if I had to I could do something like this instead:

UIActionSheet *actionSheet = nil;
if (condition1 && condition2 && condition3 && condition4) {
    actionSheet = [[[UIActionSheet alloc] initWithTitle: nil delegate: self cancelButtonTitle: @"Cancel" destructiveButtonTitle: nil otherButtonTitles: @"Do action1", @"Do action2", @"Do action3", @"Do action 4", nil] autorelease];    
} else if (condition1 && condition2 && condition3 && !condition4) {
    actionSheet = [[[UIActionSheet alloc] initWithTitle: nil delegate: self cancelButtonTitle: @"Cancel" destructiveButtonTitle: nil otherButtonTitles: @"Do action1", @"Do action2", @"Do action3", nil] autorelease];    
} 
// else ...
// about 14 other cases!

But that would be horrible. Anyone know some nice syntactic sugar to help me out?

EDIT: It has been suggested that I use addButtonWithTitle, which on the face of it looks great, unfortunately it this puts the additional buttons after the cancel button, which isn't desirable.

I believe this is bug with Apple's code since their documentation on addButtonWithTitle states:

// adds a button with the title. returns the index (0 based) of where it was added. buttons are displayed in the order added except for the
// destructive and cancel button which will be positioned based on HI requirements. buttons cannot be customized.

HI requirements (Apple's own Human Interface guidelines) favor the cancel button below all other options, so I'd say Apple screwed up. Of course, that doesn't really help me, so I'm back to trying to convert between an NSArray and a varargs, which I still don't know how to do.

like image 328
Micah Hainline Avatar asked Oct 15 '11 22:10

Micah Hainline


3 Answers

You can try this

NSMutableArray *buttonTitles = [NSMutableArray array];
if (condition1) {
    [buttonTitles addObject: @"Do action 1"];
}
if (condition2) {
    [buttonTitles addObject: @"Do action 2"];
}
if (condition3) {
    [buttonTitles addObject: @"Do action 3"];
}
if (condition4) {
    [buttonTitles addObject: @"Do action 4"];
}
[buttonTitles addObject: @"Cancel"];
UIActionSheet *actionSheet = [[[UIActionSheet alloc] initWithTitle: nil delegate: self cancelButtonTitle: nil destructiveButtonTitle: nil otherButtonTitles: nil] autorelease];

for (NSString *title in buttonTitles) {
    [actionSheet addButtonWithTitle: title];
}

[actionSheet setCancelButtonIndex: [buttonTitles count] - 1];
like image 111
Himanshu A Jadav Avatar answered Nov 19 '22 06:11

Himanshu A Jadav


A variation on Himanshu's answer:

    UIActionSheet * as = [[UIActionSheet alloc] initWithTitle:@"Share" 
                                                 delegate:self 
                                        cancelButtonTitle:nil /* don't set Cancel title here! */
                                   destructiveButtonTitle:nil 
                                        otherButtonTitles:nil];
int cancelButtonIndex = 0; // will remain 0 if no other buttons besides "Cancel"
if ( canShareBySMS )
{
    [as addButtonWithTitle:kSMSButtonText];
    cancelButtonIndex++;
}
if ( canShareByMail )
{
    [as addButtonWithTitle:kEmailButtonText];
    cancelButtonIndex++;
}
/* etc. */

// after all other buttons have been added, include Cancel
[as addButtonWithTitle:@"Cancel"];
[as setCancelButtonIndex:cancelButtonIndex];

[as showInView:self.sharingViewController.view];
[as release];

Note: your UIActionSheetDelegate method should check against button titles instead of buttonIndex:

- (void)actionSheet:(UIActionSheet *)actionSheet willDismissWithButtonIndex:(NSInteger)buttonIndex {
    if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:kSMSButtonText]) {
    //share via sms
    }else if ([[actionSheet buttonTitleAtIndex:buttonIndex] isEqualToString:kEmailButtonText]) {
    //share via mail
    }
}

I think the key detail people miss is setting the cancelButton in the initWithTitle selector, instead of adding it after all the other buttons and specifying the look of the cancel button by calling setCancelButtonIndex:.

like image 5
Code Roadie Avatar answered Nov 19 '22 05:11

Code Roadie


Why not just do something like this:

for (Nstring *button in buttonTitles)
  [actionSheet addButtonWithTitle:button];
like image 4
ennuikiller Avatar answered Nov 19 '22 05:11

ennuikiller