UIAlertController 'UIAlertAction' tag / userdata or anything in Swift

in my iOS action sheet, I show the names from the JSON dictionary:

[ { "Name": "Doctor for Disease AAA", "Doctor_id": "21" }, { "Name": "Doctor for Disease BBB", "Doctor_id": "22" }, { "Name": "Doctor for Disease AAA", "Doctor_id": "25" } ] 

So, when you do the delegate on the button, I can get the button index and you can get the corresponding "Name" and "Doctor_id". This works fine.

But now it seems that the “UIActionSheet” is out of date, and I need to use the “UIAlertController”. Since I have big data, I repeat my array values ​​and call the alertcontroller handler (so there is one function for the whole button click). But how can I get the button index from the UIAlertController so that I can get both "Name" and "Doctor_id" at the same time.

Please help me.

+6
source share
5 answers

Here you have several options.

You can use find to get UIAlertAction index

find allows you to find the index of an object in an array. You can use it to find the action index (which is passed as a parameter to the UIAlertAction handler, which is UIAlertAction itself) in the alert.actions array of all actions.

 let alert = UIAlertController(title: "Doctors", message: "Choose a doctor", preferredStyle: .ActionSheet) let closure = { (action: UIAlertAction!) -> Void in let index = find(alert.actions as! [UIAlertAction], action) println("Index: \(index)") } alert.addAction(UIAlertAction(title: "Doc1", style: .Default, handler: closure)) alert.addAction(UIAlertAction(title: "Doc2", style: .Default, handler: closure)) alert.addAction(UIAlertAction(title: "Doc3", style: .Default, handler: closure)) alert.addAction(UIAlertAction(title: "Doc4", style: .Default, handler: closure)) alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel) { _ in println("User cancelled.") }) self.presentViewController(alert, animated: true) {} 

You can create a closure ... which returns a closure

Create a closure that takes the parameter of your choice (here Int ) and returns a closure that captures this parameter so you can use it.

  let alert = UIAlertController(title: "Doctors", message: "Choose a doctor", preferredStyle: .ActionSheet) let closure = { (index: Int) in { (action: UIAlertAction!) -> Void in println("Index: \(index)") } } alert.addAction(UIAlertAction(title: "Doc1", style: .Default, handler: closure(0))) alert.addAction(UIAlertAction(title: "Doc2", style: .Default, handler: closure(1))) alert.addAction(UIAlertAction(title: "Doc3", style: .Default, handler: closure(2))) alert.addAction(UIAlertAction(title: "Doc4", style: .Default, handler: closure(3))) alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel) { _ in println("User cancelled.") }) self.presentViewController(alert, animated: true) {} 

So you have a function (closure) that generates closures for your UIAlertAction handlers, all with the same body, except that they capture another object (here Int ).

What is really great about this solution is that you can capture anything. You can even capture the hypothetical Doctor object that represents your doctor, or the doctor’s identifier directly, etc.!

Use loop

But usually you add your actions using a for loop, so why not take advantage of this, plus take advantage of the closure and the fact that they capture variables to make a nice function that will directly tell the doctor ID you select?

 func testMyAlert() { let doctors = [ ["Name": "Doctor for Disease AAA", "Doctor_id": "21"], ["Name": "Doctor for Disease BBB", "Doctor_id": "22"], ["Name": "Doctor for Disease AAA", "Doctor_id": "25"] ] chooseDoctor(doctors) { selectedDocID in if let docID = selectedDocID { println("User selected doctor with ID \(docID)") } else { println("User cancelled, no doctor selected") } } } func chooseDoctor(doctors: Array<[String:String]>, completion: Int?->Void) { let alert = UIAlertController(title: "Doctors", message: "Choose a doctor", preferredStyle: .ActionSheet) for doc in doctors { let action = UIAlertAction(title: doc["Name"]!, style: UIAlertActionStyle.Default) { _ in // On selecting this action, get the doctor ID, convert it to an Int, and return that. completion(doc["Doctor_id"]?.toInt()) } alert.addAction(action) } alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel) { _ in completion(nil) } ) self.presentViewController(alert, animated: true) {} } 
+12
source

You can solve the problem as follows:

 let arraySelect = ["NewYork", "Washington", "Seoul", "Tokyo", "Peking", "Sidney", ... ] let alert = UIAlertController(title: nil, message: nil, preferredStyle: .Alert) let closure = { (action: UIAlertAction!) -> Void in let index = alert.actions.indexOf(action) if index != nil { NSLog("Index: \(index!)") } } for var i = 0; i < arrayBibleVersions.count; i++ { alert.addAction(UIAlertAction(title: arrayBibleVersions[i][1], style: .Default, handler: closure)) } alert.addAction(UIAlertAction(title: "cancel", style: .Cancel, handler: {(_) in })) self.presentViewController(alert, animated: false, completion: nil) 
+4
source

You can call indexOf(element: Self.Generator.Element) in your action collection from your controller.

Sort of:

 let actionSheetController = UIAlertController(title: "Title", message: "Select Title", preferredStyle: UIAlertControllerStyle.ActionSheet); for entry in data { let myAction = UIAlertAction(title: "title: \(entry)", style: UIAlertActionStyle.Default) { (action) -> Void in if let alertIndex = actionSheetController.actions.indexOf(action) { print("actionIndex: \(alertIndex)") } } actionSheetController.addAction(myAction) } 
+1
source

I suggest you hand over the closure to call when you need it. Its on demand. Perhaps something like this will help.

 var alert = UIAlertController(title: "Title", message: "do this", preferredStyle: UIAlertControllerStyle.ActionSheet) var action = UIAlertAction(title: "Doc1", style: UIAlertActionStyle.Default) { (action) -> Void in //do some work here } 

But then again, I think you are not showing more than 4 elements on the action sheet, because it is bad for design. closing may be a good idea. Suggest me, if I am wrong, I would like to help you. Greetings.

0
source

You add buttons to the UIAlertController by creating one or more UIAlertAction objects and attaching them to the alert controller. Each warning action has a title (used to create it) and a closure that is called when the user clicks this button.

Are you saying you want to use the same closure for all of your buttons? I see several options

  • You can write unique closures for each action to alert when the closure simply calls a common function and passes the button number.

  • Alternatively, closing the UIAlertAction is passed in the header of the button that was clicked. You can use this to decide which button was pressed. (This is fragile because button names can be localized and can be changed for user interface purposes. It is bad when the user interface changes the interrupt code.)

  • As a final option, you can use associative storage to attach an object to each UIAlertAction and use it to determine which button was clicked.

My suggestion is option 1. It is simple and clean.

0
source

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


All Articles