1

I have a Swift app that I am trying to update the location when the app is returned from the background, but it doesn't seem to work when returned from the background.

On launch of the app, I'll get the location just fine. After getting the location I call stopUpdatingLocation() so I don't continue to get the location: locationManager.stopUpdatingLocation()

Then, in my AppDelegate.swift I startUpdatingLocation again:

func applicationWillEnterForeground(application: UIApplication) {

    ViewController().locationManager.startUpdatingLocation()
}

This is my code so far:

import UIKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate {

var locationManager = CLLocationManager()

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

    locationManager.delegate = self
    locationManager.desiredAccuracy = kCLLocationAccuracyBest
    locationManager.requestWhenInUseAuthorization()
    locationManager.startUpdatingLocation()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
    println("Error while updating location " + error.localizedDescription)
}

func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {

    var userLocation:CLLocation = locations[0] as CLLocation

    println("\(userLocation.coordinate.latitude),\(userLocation.coordinate.longitude)")

    locationManager.stopUpdatingLocation()

}

}

However, whenever I background the app (click home), and then return to the app the location isn't updated. Any idea what I might be doing wrong here?

Dave Moz
  • 127
  • 1
  • 1
  • 6

1 Answers1

2

In applicationWillEnterForeground, the code is creating a new, local instance of ViewController that is never displayed, does not yet have a locationManager created and so has no effect.

It is not referring to the ViewController instance that already exists and is displayed (and has the locationManager instance that was originally started).

Instead, it should get a reference to the existing instance. Assuming ViewController is the root view controller, you could do:

func applicationWillEnterForeground(application: UIApplication) {

    if let rvc = window?.rootViewController as? ViewController {
        rvc.locationManager.startUpdatingLocation()
    }

}


However, it might be better practice to let the ViewController class itself manage its own behavior. This way, the app delegate doesn't have to find a reference to the view controller's instance and it doesn't directly access the view controller's internal state and ViewController becomes more self-contained.

In addition to the app delegate method applicationWillEnterForeground, it's possible to monitor these events from anywhere using the UIApplicationWillEnterForegroundNotification notification.

In ViewController, you can register and unregister for the notification in (for example) viewWillAppear and viewWillDisappear. When registering, you indicate which method to call for the event and everything is handled inside ViewController (and the code in applicationWillEnterForeground can be removed).

override func viewWillAppear(animated: Bool) {
    NSNotificationCenter.defaultCenter().addObserver(
        self, 
        selector: "willEnterForegound", 
        name: UIApplicationWillEnterForegroundNotification, 
        object: nil)
}

override func viewWillDisappear(animated: Bool) {
    NSNotificationCenter.defaultCenter().removeObserver(
        self, 
        name: UIApplicationWillEnterForegroundNotification, 
        object: nil)
}

func willEnterForegound() {
    locationManager.startUpdatingLocation()
}
  • Thanks Anna, makes perfect sense, not sure how I missed that it was creating a new instance of ViewController, not using the existing. – Dave Moz Feb 23 '15 at 15:24