Reputation: 87
I have an UIViewController extension which I am using to display alerts in any view controller. It worked fine until this weird use case happened:
extension UIViewController {
func showModal(title: String, msg: String, handler: ((UIAlertAction) -> Void)? = nil) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: handler))
DispatchQueue.main.async {
self.present(alert, animated: true, completion: nil)
}
}
}
Inside a view controller I tap a button which triggers a network fetch:
@IBAction func didTapSave(_ sender: UIButton) {
Task {
let result = await BalanceManager.shared.fetchAllBalances()
switch result {
case .success(_):
self.showModal(title: "", msg: "account successfully saved") { (_) in
//This code always gets executed
self.navigationController?.popViewController(animated: true)
}
case .failure(let failure):
self.showModal(title: "", msg: "failure") { (_) in
//Code in here is not executed
print("Failure closure")
}
}
}
I don't understand why on case ".failure" the closure for showModal does not execute. If I set a breakpoint on the line with self.showModal the code gets there but does not execute the closure when I tap "OK" on the popup
Upvotes: 0
Views: 163
Reputation: 87
I figured it out, it was my programming mistake and lack of proper sleep :). Another VC which was listening for notifications about the result of the same fetch was triggering a popup even though the VC was not visible, but was alive, embedded in a tab bar controller. So my "failure" popup was never executed properly. I figured it out after I updated the showModal method with the sender parameter and following that I have added a fix that requires the calling VC to be visible when it wants to present a popup:
func showModal(sender: UIViewController, title: String, msg: String, handler: ((UIAlertAction) -> Void)? = nil) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: handler))
DispatchQueue.main.async {
if sender.isVisible() {
self.present(alert, animated: true, completion: nil)
}
}
}
where isVisible():
extension UIViewController {
func isVisible() -> Bool {
return self.isViewLoaded && self.view.window != nil
}
}
Upvotes: 0