Reputation: 35953
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?
Upvotes: 4
Views: 3364
Reputation: 8571
Old question, but with iOS 8, the new UIAlertController
class, allows you to create UIAlertAction
s using blocks:
let alertController = UIAlertController(title: "Pancakes", message: "Do you like them with:", preferredStyle: .ActionSheet)
alertController.addAction(UIAlertAction(title: "Maple Syrup", style: .Default, handler: { (alert) -> Void in
println("Picked syrup")
}))
alertController.addAction(UIAlertAction(title: "Jam", style: .Default, handler: { (alert) -> Void in
println("Jam? eh?")
}))
alertController.addAction(UIAlertAction(title: "I HATE PANCAKES", style: .Destructive, handler: { (alert) -> Void in
println("You monster.")
}))
Upvotes: 0
Reputation: 32681
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
}
}];
switch/case
on NSStringsNote 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 */
})();
Upvotes: 5
Reputation: 9382
Sorry for adding a late answer for such an old question, but googling "UIActionSheet blocks" leads here so I thought I'd share with you this easy block implementation I wrote.
https://github.com/freak4pc/UIActionSheet-Blocks
Cheers!
Upvotes: 0
Reputation: 5552
I prefer to help (although not fully solve) this problem by using an array of values. It makes it so that you at least have a unified source of data. So by creating an array for your values in your viewDidLoad or whatever and when you create your action sheet you can change it to something like:
//where myValuesArray is an array of strings you declared in viewDidLoad
//myValuesArray = [NSArray arrayWithObjects:@"aaa", @"bbb", @"ccc", @"ddd", nil];
UIActionSheet * myChoices = [[UIActionSheet alloc]
initWithTitle:nil
delegate:self
cancelButtonTitle:@"cancel"
destructiveButtonTitle:@"erase"
otherButtonTitles:nil];
for(NSString *title in myValuesArray)
{
[myChoices addButtonWithTitle:@"LMNOP"];
}
Then in your clickedButtonAtIndex you are checking against the index of the exact same array with what I assume is your choices. With this you can also just update the array when you want to make changes. I hope this helps.
Upvotes: 3