1

Struggling with the following code:

 var connected = false
    while !connected {
        let msg = "Press cancel"
        let alert = UIAlertController(title: "Test", message: msg, preferredStyle: .alert)
        let action = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
            connected = true
        }
        alert.addAction(action)
        print ("Hello")
        present(alert, animated: true, completion: nil)

    }
  1. The UIAlertController is never shown, "Hello" is printed over and over again
  2. If I insert "connected = true" after the while clause then the UIAlertController is shown, but I'm not able to show it again by changing the action to "connected = false"

What am I doing wrong?

  • 2
    Why do you keep showing the alert controller in a endless loop? Think it it's not reasonable. Keep the logic just show the alert controller in specific condition. – William Hu Sep 10 '17 at 13:23
  • 1
    Once you break out of the while loop it will not be executed any more. And what William is saying is true, please don't do this. – Marcel Sep 10 '17 at 13:47
  • Well, it was just an example, what I would like to do was the user to leave the app and connect to an external wireless network and have a "Try again" button to check it the connection was ok. Hence, instead of "connection = true" I would have a something like " if networkOk {connected = true} If not ok, show the alert controller again... – Tom Widerøe Sep 10 '17 at 14:02

3 Answers3

2

First of all, as mentioned in the comments, its not a good idea to present your alert controller continuously in a while loop. I believe your intended functionality is to display an alert whenever the connected variable becomes false.

To accomplish this use NotificationCenter to respond as follows:

In viewDidLoad:

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.displayAlert), name: NSNotification.Name(rawValue: "connectionDropped"), object: nil)

Add a willSet property observer to connected:

var connected: Bool! {
  willSet {
    if newValue == false && oldValue != false {
      NotificationCenter.default.post(name: NSNotification.Name(rawValue: "connectionDropped"), object: nil)
    }
  }
}

Then whenever you set self.connected = false, you will run this method:

@objc func displayAlert() {
  let msg = "Press cancel"
  let alert = UIAlertController(title: "Test", message: msg, preferredStyle: .alert)
  let action = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
    self.connected = true
  }
  alert.addAction(action)
  print ("Hello")
  present(alert, animated: true, completion: nil)
}

Just make sure you set connected after the view hierarchy has been loaded e.g in viewDidAppear.

Once you're done with the view you can then remove the observer:

deinit {
  NotificationCenter.default.removeObserver(self, name: NSNotification.Name(rawValue: "connectionDropped"), object: nil)
}

EDIT:

The functionality you need is provided with the Reachability framework, in particular with the reachabilityChanged notification. You can then call the displayAlert using a similar approach that I outlined above; this is documented on their README document.

Pranav Kasetti
  • 8,770
  • 2
  • 50
  • 71
0
  1. The UIAlertController is never shown, "Hello" is printed over and over again

It is inappropriate to keep presenting the alert in an endless while loop, probably, it leads to facing "AlertController is not in the window hierarchy" issue.

  1. If I insert "connected = true" after the while clause then the UIAlertController is shown, but I'm not able to show it again by changing the action to "connected = false"

Of course you won't be able to show it again by default, the chunk of code is already been executed.

Solution:

Presenting the alert should be related to triggering a specific condition, not in a while loop.

For instance, if you are aiming to notify the user that the device is unconnected, You could use Reachability and observe reachabilityChanged to present the alert, for more details you could check the library - Example - notifications section.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
0

I managed to solve it using a recursive call to the function:

    func showDlg(){
    ssid = getWiFiSsid() ?? "AAA"
    ssid = ssid[ssid.startIndex..<ssid.index(ssid.startIndex, offsetBy: 2)]
    if ssid != "GP" {
        print ("SSID: " + ssid)

        let msg = "\nNot connected to GoPro camera\n\nPlease connect to camera wireless network and revert\n "
        alert = UIAlertController(title: "GoPro Golfswing Analyser", message: msg, preferredStyle: .alert)
        let action = UIAlertAction(title: "Try again", style: .default) { (action:UIAlertAction) in
            print("Testing network again")
            self.showDlg()
        }
        alert.addAction(action)

        let action1 = UIAlertAction(title: "Cancel", style: .default) { (action:UIAlertAction) in
            print("Cancel - exiting")

        }
        alert.addAction(action1)

        present(alert, animated: true, completion: nil)

    } else{
        print("Connected to GoPro")
    }

}