Syed Tariq
Syed Tariq

Reputation: 2918

Unusual behavior with UIAlertViewController

I have a simple use of UIAlertViewController in which I pass button labels and action functions as arguments to a function named showAlert() which sets up and invokes the alert. I have action function in UIAlertAction in the in closure.

Unusual behavior: The action function gets executed as soon as the showAlert is executed instead of when the button is pressed.

The other issue is that the alert gets dismissed automatically when a button is pressed. I do not have dismiss statement.

    class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    func test1() {
        NSLog("test 1 executed")
    }




    @IBAction func show(_ sender: UIButton) {
        self.showAlert(title: "Title", message: "Message",titleString: "A,B,C", function:test1())
    }
    func showAlert(title: String, message: String, titleString: String, function: ()) {
        let cancelButtonTitle = NSLocalizedString("Cancel", comment: "")
        let labels = titleString.components(separatedBy: ",")
        var actions = [UIAlertAction()]
        for label in labels {
            let a = UIAlertAction(title: label, style: .default) { action in
                function // executed as soon as showAlert is called!! 
                         // Expecting to be called when button is pressed
                NSLog("\(label) Pressed")

            }
            actions.append(a)
        }

        let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)

        // Create the actions.
        let cancelAction = UIAlertAction(title: cancelButtonTitle, style: .cancel) { action in
            NSLog("Cancel Button pressed.")
        }
        for action in actions {
            alertController.addAction(action)
        }
        // Add the actions.
        alertController.addAction(cancelAction)

        present(alertController, animated: true, completion: nil)
    }

}

The response on the console is: 2017-05-11 11:55:15.593 AlertTest[5304:8818290] function executed 2017-05-11 11:55:25.287 AlertTest[5304:8818290] A Pressed

Upvotes: 0

Views: 32

Answers (1)

Sweeper
Sweeper

Reputation: 271420

Remember this:

Adding ()s to the end of a method/function name will call the method. Remove the ()s to "refer" to that method/function.

When you are doing this:

//                                                                           I mean this
//                                                                                 |
//                                                                                 v 
self.showAlert(title: "Title", message: "Message",titleString: "A,B,C", function:test1())

You are calling test and using its return value as the argument to showAlert.

When that line is reached, test() is called first to evaluate its return value, then showAlert is called, hence the console output.

To refer to the method test, remove the ()s.

self.showAlert(title: "Title", message: "Message",titleString: "A,B,C", function:test1)

You also wrote the parameter type wrong. The type of function that takes no parameters and returns nothing should be () -> Void:

func showAlert(title: String, message: String, 
    titleString: String, function: () -> Void) {

Also, in the alert closure, add the ()s to the function because you are now trying to call it:

let a = UIAlertAction(title: label, style: .default) { action in
    function() // Note the ()s
    NSLog("\(label) Pressed")

}

P.S. I don't think having all the buttons do the same thing is what you really want. I might be wrong though.

Upvotes: 1

Related Questions