Search code examples
iosswiftalertuialertcontrolleruialertaction

Swift UIKit - Showing an alert after another one


I am trying to show an alert after another one in swift. I found a solution but I think this is not the true way. My code piece is below.

With this code, alerts can be shown in the view.

override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let person = people[indexPath.item]
    
    let questionAc = UIAlertController(title: "What is your purpose?", message: "", preferredStyle: .alert)
    let deleteButton = UIAlertAction(title: "Delete", style: UIAlertAction.Style.destructive) { [weak self] _ in
        
        self?.people.remove(at: indexPath.item)
        collectionView.reloadData()
    }
    
    let renameButton = UIAlertAction(title: "Rename", style: .default) { [weak self] _ in
        
        let ac = UIAlertController(title: "Rename person", message: nil, preferredStyle: .alert)
        ac.addTextField()
        ac.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        ac.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak self, weak ac] _ in
            guard let newName = ac?.textFields?[0].text else {return}
            person.name = newName
            self?.collectionView.reloadData()
        }))

        self?.present(ac, animated: true)
        
    }
    
    questionAc.addAction(deleteButton)
    questionAc.addAction(renameButton)
    present(questionAc, animated: true) 
}

As you know, if I directly add my alert code after the first one, it doesn't work. But if I put my second one's code to first one's action, it does.

However, in this case, I need to connect one alert to another one's button's action. I don't want to connect it to another one.

Is there any solution for better way showing alerts in the same view, orderly?

Thank you.


Solution

  • Presenting the second alert works when done in the handler of one of the first alert's actions because the handler is executed after the alert is dismissed.

    With this in mind, you just need to dismiss your first alert then present your second alert in the completion block of the dismissal call, for example:

    (Here we just wait 2.5 seconds before presenting the second alert)

    func showAlert1() {
        let alert = UIAlertController(title: "Alert!", message: "I am alert number 1", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Action", style: .default, handler: { _ in
            print("Alert 1 action pressed")
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    
        present(alert, animated: true)
    
        // Wait 2.5 seconds then dismiss the first alert and present the second alert
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(2500), execute: { [weak self] in
            alert.dismiss(animated: true) {
                self?.showAlert2()
            }
        })
    }
    

    If you want the first alert to remain open (so that it is still visible when the second alert is dismissed) you can just use the first alert as the presenting ViewController for example:

    func showAlert1() {
        let alert = UIAlertController(title: "Alert!", message: "I am alert number 1", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Action", style: .default, handler: { _ in
            print("Alert 1 action pressed")
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
    
        // Wait 2.5 seconds then present the second alert
        DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(2500), execute: {
            self.showAlert2(from: alert)
        })
    
        present(alert, animated: true)
    }
    
    func showAlert2(from viewController: UIViewController) {
        let alert = UIAlertController(title: "Alert!", message: "I am alert number 2", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "Action", style: .default, handler: { _ in
            print("Alert 2 action pressed")
        }))
        alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
        viewController.present(alert, animated: true)
    }