Elegant solution for UIActionSheet mess
ios, ipad, iphone
Solution
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 */
})();
Problem
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?