59

I have the following function working as I expect, in iOS 8:

func showConfirmBox(msg:String, title:String, firstBtnStr:String, secondBtnStr:String, caller:UIViewController) { let userPopUp = UIAlertController(title:title, message:msg, preferredStyle:UIAlertControllerStyle.Alert) userPopUp.addAction(UIAlertAction(title:firstBtnStr, style:UIAlertActionStyle.Default, handler:{action in})) userPopUp.addAction(UIAlertAction(title:secondBtnStr, style:UIAlertActionStyle.Default, handler:{action in})) caller.presentViewController(userPopUp, animated: true, completion: nil) } 

I would like to make something like the following, in order to pass as arguments the methods to be executed when one or the other of the buttons are going to be touched:

func showConfirmBox(msg:String, title:String, firstBtnStr:String, firstSelector:Selector, secondBtnStr:String, secondSelector:Selector, caller:UIViewController) { let userPopUp = UIAlertController(title:title, message:msg, preferredStyle:UIAlertControllerStyle.Alert) userPopUp.addAction(UIAlertAction(title:firstBtnStr, style:UIAlertActionStyle.Default, handler:{action in caller.firstSelector()})) userPopUp.addAction(UIAlertAction(title:secondBtnStr, style:UIAlertActionStyle.Default, handler:{action in caller.secondSelector()})) caller.presentViewController(userPopUp, animated: true, completion: nil) } 

Obviously I am not doing the right thing with firstSelector and secondSelector, because what I have tried up to now did not work. I suppose I am not using the right syntax for what I want, but I am sure it is possible to do what I would like to do. Any idea of the way to do it properly?

4
  • What do you mean "did not work"? Please provide more specific information. Commented Nov 15, 2015 at 7:27
  • What I mean is that I get error messages, from the compiler. I could include those if it is useful. Rather than that I suppose the syntax in my 2nd function is just wrong. Commented Nov 15, 2015 at 7:37
  • I am trying on my own to find other ways (using generics for example) but at this point still without success. Commented Nov 15, 2015 at 7:40
  • 1
    Now it works I figured it out. Just : Using the function name and no quotes. Thanks! Commented Nov 15, 2015 at 8:00

4 Answers 4

103

Oneword answer for your question is Closures

The Default Syntax for closures is () -> ()

Instead of Selector you could directly mention the method definition

func showConfirmBox(msg:String, title:String, firstBtnStr:String, firstSelector:(sampleParameter: String) -> returntype, secondBtnStr:String, secondSelector:() -> returntype, caller:UIViewController) { //Your Code } 

But using this will create readability problems so i suggest you to use typeAlias

typealias MethodHandler1 = (sampleParameter : String) -> Void typealias MethodHandler2 = () -> Void func showConfirmBox(msg:String, title:String, firstBtnStr:String, firstSelector:MethodHandler1, secondBtnStr:String, secondSelector:MethodHandler2) { // After any asynchronous call // Call any of your closures based on your logic like this firstSelector("FirstButtonString") secondSelector() } 

You can call your method like this

func anyMethod() { //Some other logic showConfirmBox(msg: "msg", title: "title", firstBtnStr: "btnString", firstSelector: { (firstSelectorString) in print(firstSelectorString) //this prints FirstButtonString }, secondBtnStr: "btnstring") { //Invocation comes here after secondSelector is called } } 
Sign up to request clarification or add additional context in comments.

1 Comment

Since Swift 3, you cannot assign argument labels to function types. So MethodHandler1 should be written like this: "typealias MethodHandler1 = (String) -> Void". Referenced from here: stackoverflow.com/a/39717607/380316
17

Just in case anyone else stumbles upon this. I worked out an updated simple solution for Swift 5.1 while I was working through this for while building a global alert utility for a project.

Swift 5.1

Function with Closure:

func showSheetAlertWithOneAction(messageText: String, dismissButtonText: String, actionButtonText : String, presentingView : NSWindow, actionButtonClosure: @escaping () -> Void) { let alert = NSAlert() alert.messageText = messageText alert.addButton(withTitle: actionButtonText) alert.addButton(withTitle: dismissButtonText) alert.beginSheetModal(for: presentingView) { (response) in if response == .alertFirstButtonReturn { actionButtonClosure() } } } 

Function Called:

showSheetAlertWithOneAction(messageText: "Here's a message", dismissButtonText: "Nope", actionButtonText: "Okay", presentingView: self.view.window!) { someFunction() } 

Comments

12

Adding to got2jam's answer... If you're working with UIAlertController

The generic function to show an alert with closure:

func showAlertAction(title: String, message: String, actionClosure: @escaping () -> Void){ let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: {(action: UIAlertAction!) in actionClosure()})) self.present(alertController, animated: true, completion: nil) } 

Now you can call it like that:

showAlertAction(title: "This is the title", message: "This is the message") { self.close() } 

in this case, close is the particular UIAlertAction to execute

func close(){ dismiss(animated: true, completion: nil) } 

1 Comment

I've got a UIAlertController with two UITextFields (called by different UIViewControllers), which makes everything a bit more complicated. To return the input data to the calling function, add it to the closure with actionClosure: @escaping (_ input1:String, _input2:String) and finally pass it with actionClosure("Hello","World"). If you want to check the input for validity, then do that between in and actionClosure().
0

I wrote this routine based on various site examples. Here is how I call the routine...

@IBAction func buttonClick(_ sender: Any) { SS_Alert.createAlert(parmTitle: "Choose", parmMessage: "Please select Yes or No", parmOptions: ["Yes","No","Cancel"], parmFunctions: [testYes, testNo, nil]) } func testYes() { print("yes") } func testNo() { print("no") } 

You can pass in button options and the functions to performed when the buttons are selected. Took a little time to figure out how to pass functions as parameters, but appears to work fine now. I did encounter a strange problem trying to use loops to dynamically add buttons, and finally gave up and used a switch/case. I included the loop code I tried to use, if someone can figure out what I was doing wrong let me know. Thanks.

https://github.com/blakeguitar/iOS/blob/0e243d13cb2decd6e1dbe134a8a046c2caed3876/SS_Alert.swift

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.