Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Elegant solution for UIActionSheet mess

Tags:

ios

iphone

ipad

I am trying to find an elegant solution to UIActionSheet problem.

I use UIActionSheets like this:

UIActionSheet * myChoices = [[UIActionSheet alloc]
    initWithTitle:nil
    delegate:self
    cancelButtonTitle:@"cancel"
    destructiveButtonTitle:@"erase"
    otherButtonTitles: @"aaa", @"bbb", @"ccc", @"ddd", nil]; 

the problem is that in order to discover the option selected by the user, I have to use this:

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {

    switch ([actionSheet tag]) {
           case 0: ... 
           case 1: ... 
           case 2: ... 
           case 3: ... 

        }
}

this case based on index is terrible, because if I change the order of the aaa, bbb, ccc, etc., on the action sheet I have to change the case order. This index stuff is not good as a solid solution.

I have tried to imagine a way to do that and become index independent but did not come any satisfactory solution. Using buttonTitleAtIndex is not good enough too, because my apps are localized and I would have to test for n titles for every entry. Any suggestions?

like image 527
Duck Avatar asked Feb 18 '23 17:02

Duck


1 Answers

Since I created a block-based version of UIAlertView and UIActionSheet, I personally never use the delegate-based Apple version again.
You can download my OHActionSheet and OHAlertView classes in my GitHub repository.

Because they are based on the completionBlock pattern, they are more readable (all the code is at the same place, no common delegate for multiple UIActionSheets, …), and more powerful (because blocks also capture their context as needed).

NSArray* otherButtons = @[ @"aaa", @"bbb", @"ccc", @"ddd" ];
[OHActionSheet showSheetInView:self.view
                         title:nil
             cancelButtonTitle:@"cancel"
        destructiveButtonTitle:@"erase"
             otherButtonTitles:otherButtons
        completion:^(OHActionSheet* sheet, NSInteger buttonIndex)
 {
   if (buttonIndex == sheet.cancelButtonIndex) {
     // cancel
   } else if (buttonIndex == sheet.destructiveButtonIndex) {
     // erase
   } else {
     NSUInteger idx = buttonIndex - sheet.firstOtherButtonIndex;
     // Some magic here: thanks to the blocks capturing capability,
     // the "otherButtons" array is accessible in the completion block!
     NSString* buttonName = otherButtons[idx];
     // Do whatever you want with idx and buttonName
   }
 }];

Additional Note: how to switch/case on NSStrings

Note that in the otherButtons part of the if/else test in your completion handler, you can then either test for the idx using a switch/case, or use my ObjcSwitch category, that will allow you to write switch/case-like code but for NSStrings, so you can have a code like this in your OHActionSheet's completion handler:

NSUInteger idx = buttonIndex - sheet.firstOtherButtonIndex;
NSString* buttonName = otherButtons[idx];
[buttonName switchCase:
   @"aaa", ^{ /* Some code here to execute for the "aaa" button */ },
   @"bbb", ^{ /* Some code here to execute for the "bbb" button */ },
   @"ccc", ^{ /* Some code here to execute for the "ccc" button */ },
   ..., nil
];

EDIT : Now that the latest LLVM compiler supports the new "Object Literals" syntax, you can do the same as ObjcSwitch using the compact syntax of an NSDictionary:

((dispatch_block_t)@{
   @"aaa": ^{ /* Some code here to execute for the "aaa" button */ },
   @"bbb": ^{ /* Some code here to execute for the "bbb" button */ },
   @"ccc": ^{ /* Some code here to execute for the "ccc" button */ },
}[buttonName] ?:^{
       /* Some code here to execute for defaults if no case found above */
})();
like image 137
AliSoftware Avatar answered Feb 27 '23 12:02

AliSoftware