Elegant solution for UIActionSheet mess

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

I use UIActionSheets as follows:

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 detect a parameter 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 index based case is terrible because if I change the order of aaa, bbb, ccc, etc., in the action sheet I need to change the order of things. This index is not a good solution as a solid solution.

I tried to imagine a way to do this and become independent of the index, but did not find a satisfactory solution. Using buttonTitleAtIndex is also not enough, because my applications are localized, and I will need to check n headers for each entry. Any suggestions?

+4
source share
4 answers

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

Since they are based on the Block completion pattern, they are more readable (all code is in one place, there is no common delegate for several UIActionSheets , ...) and more powerful (since blocks also fix 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: like switch/case on NSStrings

Note that in the otherButtons part of the if/else test in your completion handler, you can either test idx using switch/case or use the ObjcSwitch category , which allows you to write switch/case code, but for NSStrings , so you can have such code in its OHActionSheet 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 NSDictionary syntax:

 ((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 */ })(); 
+5
source

I prefer to help (although not completely solve) this problem using an array of values. This makes it possible that you have at least a single data source. Therefore, by creating an array for your values ​​in your DidLoad view 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 check the index of the same array with what I assume is your choice. With this, you can also just update the array whenever you want to make changes. Hope this helps.

+3
source

Sorry to add a late answer to such an old question, but googling "UIActionSheet blocks" leads here, so I decided to share with you this simple block implementation that I wrote.

https://github.com/freak4pc/UIActionSheet-Blocks

Hooray!

0
source

An old question, but with iOS 8, the new UIAlertController class allows you to create UIAlertAction 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.") })) 
0
source

Source: https://habr.com/ru/post/1441877/


All Articles