Swift 3: Checking Internet (Reocurring) viewDidAppear not
Asked Answered
L

3

8

Ok, So I am rather new to Swift and I am a little confused about what I am trying to do, or if I am going in the wrong direction. (https://github.com/ashleymills/Reachability.swift)

Here is my viewDidLoad method :

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    checkConnection()

}

I then have a function with the code in from the Reachability GitHub Project:

func checkConnection() {
    //declare this property where it won't go out of scope relative to your listener
    let reachability = Reachability()!

    reachability.whenReachable = { reachability in
        // this is called on a background thread, but UI updates must
        // be on the main thread, like this:
        DispatchQueue.main.async {
            if reachability.isReachableViaWiFi {
                print("Reachable via WiFi")
            } else {
                print("Reachable via Cellular")
            }
        }
    }
    reachability.whenUnreachable = { reachability in
        // this is called on a background thread, but UI updates must
        // be on the main thread, like this:
        DispatchQueue.main.async {

            self.dim(direction: .In, alpha: self.dimLevel, speed: self.dimSpeed)
            self.performSegue(withIdentifier: "mainToAlertNoInternet", sender:  self)
        }
    }

    do {
        try reachability.startNotifier()
    } catch {
        print("Unable to start notifier")
    }
}

As you can see, when there is no internet, this is the code:

self.dim(direction: .In, alpha: self.dimLevel, speed: self.dimSpeed)
            self.performSegue(withIdentifier: "mainToAlertNoInternet", sender:  self)

The Dim is taken from (http://www.totem.training/swift-ios-tips-tricks-tutorials-blog/ux-chops-dim-the-lights) the mainToAlertNoInternet loads the next view over the current one with transparence so it is an alert style.

So, the second segue has a view and a button on it. Nothing spectacular this is what is loaded when there is no internet:

enter image description here

That try again button is linked to the Exit of the Segue and runs this function in the First View Controller:

@IBAction func unwindFromSecondary(segue: UIStoryboardSegue) {
    dim(direction: .Out, speed: dimSpeed)
    checkInternetConnection()
}

I added in the function mainToAlertNoInternet so that when they click try again, it will go back to the first segue and run the test again. However, When I click try again, I get this error:

Warning: Attempt to present on whose view is not in the window hierarchy!

Hopefully I have explained enough what I have set up. Now to the Questions:

1) How can I fix this error? 2) Am I doing this the right way or is there a better way?

This is what I want:

I want to check the internet connection the moment the app loads. If there is no connection I want to display the segue like I have been doing. If the user clicks Try gain, I want it to go back to the first controller and run the check again and if still no connection display the segue like it did initially again. I would like this to be a repeating process until there is internet.

Appreciate all your help. Thanks in advance

Edit:

I have added the function call in the ViewDidAppear method like so:

override func viewDidAppear(_ animated: Bool) {
    checkInternetConnection()
}

However, it does not run. Also the DIM in the unwindFromSecondary function does not get called when I do this.

Edit 2:

Just added this line into my viewDidAppear:

print("Appeared")

This gets called initially, but then not again.

Question:

How do I get a function to run once everything has loaded again after the unwindSegue?

Any thoughts?

Update 3

Ok, so I have looked at the answers below:

@MarkP Answer works fine. Thank you for that However, the answer from @iSee has got me thinking maybe I should be going about this a different way.

I have added a Bounty to this post for a detailed answer that can show me and explain how to achieve the following:

In my app. I need to keep making sure that the internet exists (Maybe a Timer) on any view that loads. I would like it so that like the current way, If there is no internet it will pop up the ViewController with this segue:

performSegue(withIdentifier: "mainToAlertNoInernet", sender: self)

It appears that the App Delegate would be the place but I am unsure how to achieve this.

I am new to iOS Development and thus would appreciate some explanation and teaching.

Thank you for your time. It is greatly appreciated.

Luminescence answered 17/9, 2016 at 14:20 Comment(1)
Possible duplicate of whose view is not in the window hierarchyMeaghanmeagher
S
2

As @iSee has pointed out with the links. This is because the view has not been added to the view hierarchy so you can't move to it. for this self.dismissViewControllerAnimated is needed:

@IBAction func unwindFromSecondary(segue: UIStoryboardSegue) {
    dim(direction: .Out, speed: dimSpeed)
    self.dismiss(animated: true) {
        self.checkInternetConnection()
    }

}
Shag answered 18/9, 2016 at 23:22 Comment(0)
A
3

I presume you are new to iOS development in general.

  1. The warning has nothing to do with your internet connectivity code.

  2. The Warning you are getting is not an error. It is just that, a warning.

  3. The reason you are getting that is well explained in this link and this
  4. To get rid of that warning, you should not call performSegue from viewDidLoad(refer to the above link for more information.
  5. To perform your network checks, it is advisable to use the AppDelegate (gives you a better control over the flow of the app)

All the best :)

EDIT: Please refer to this link here for more information on this. I could easily repost it here but since it is already answered, you can refer to the above link as to why it happens and how to avoid it.

Antabuse answered 17/9, 2016 at 15:12 Comment(1)
yes you are right, I am new to iOS Dev in general. Do you think you could be a little more specific in what I need to do?Luminescence
S
2

As @iSee has pointed out with the links. This is because the view has not been added to the view hierarchy so you can't move to it. for this self.dismissViewControllerAnimated is needed:

@IBAction func unwindFromSecondary(segue: UIStoryboardSegue) {
    dim(direction: .Out, speed: dimSpeed)
    self.dismiss(animated: true) {
        self.checkInternetConnection()
    }

}
Shag answered 18/9, 2016 at 23:22 Comment(0)
A
0

I use this in the app delegate ->

 func reachablityCode() {
        AFNetworkReachabilityManager.sharedManager()
        AFNetworkReachabilityManager.sharedManager().startMonitoring()
        AFNetworkReachabilityManager.sharedManager().setReachabilityStatusChangeBlock({(status) in
            let defaults = NSUserDefaults.standardUserDefaults()
            if status == .NotReachable {
                defaults.setBool(false, forKey:REACHABLE_KEY)
            }
            else {
                defaults.setBool(false, forKey: REACHABLE_KEY)
            }
            defaults.synchronize()
        })
    }

And then this in the base file ->

 func isReachable() -> Bool {
        return NSUserDefaults.standardUserDefaults().boolForKey(REACHABLE_KEY)
    }
Ardel answered 19/9, 2016 at 6:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.