Search code examples
iosswiftswift4

locationManager.stopUpdateLocations doesn't work after the app returns from the background state


I use geolocation tracking in the background, after a few minutes when the app is in the background, the call to locationManager.stopUpdateLocations () stops working - the blue bar on top is not removed and the app continues to use geolocation services. If you call locationManager.stopUpdateLocations() without minimizing the app to the background, the services are turned off and the blue bar on top disappears. Anyone who has encountered this, please help, spent several days already - all to no avail. Disabled all the logic, all that remains is: starting geolocation services (locationManager.startUpdateLocations) and trying to stop( locationManager.stopUpdateLocations). No timers or any other logic at all.

import CoreLocation

final class MyLocationService: NSObject, CLLocationManagerDelegate {

    private let locationManager = CLLocationManager()
    

    func sendCoord() {
        print("Send you coordinates")
    }
    
    func requestPermission() {
        locationManager.requestWhenInUseAuthorization()
    }
    
    func start() {
        locationManager.delegate = self
        locationManager.pausesLocationUpdatesAutomatically = false
        locationManager.allowsBackgroundLocationUpdates = true
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.distanceFilter = 300
        locationManager.startUpdatingLocation()
        
        sendCoord()
        
    }
    
    func stop() {

        locationManager.pausesLocationUpdatesAutomatically = true
        locationManager.stopUpdatingLocation()
        locationManager.allowsBackgroundLocationUpdates = false
        locationManager.delegate = nil 
    }
    
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    
        sendCoord()
    }
}

This is my ViewController class:

import UIKit
import Foundation
import CoreLocation

class ViewController: UIViewController {
        
    // *** Internal variables *** //
    private let locationService = MyLocationService()
    var needPermissionForLocationServices = false

    @IBOutlet weak var toolBar: UIToolbar!
    
    @IBOutlet weak var startLocationToolBarButton: UIBarButtonItem!
    
    @IBAction func startLocationToolBarButtonAction(_ sender: UIBarButtonItem) {
        
    if CLLocationManager.locationServicesEnabled() {

            switch(CLLocationManager.authorizationStatus()) {

                case .notDetermined, .restricted, .denied:
           
                    DispatchQueue.main.async(execute: {

                        let alert = UIAlertController(title: "Error!", message: "Location services is off", preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "Go to settings?", style: UIAlertAction.Style.default, handler: { (alert: UIAlertAction!) in
                print("")
                            UIApplication.shared.open(NSURL(string:UIApplication.openSettingsURLString)! as URL)
                        }))
                        self.present(alert, animated: true, completion: nil)
                    })
                    
                case .authorizedAlways, .authorizedWhenInUse:

                    locationService.start()
                }
            } else {
                DispatchQueue.main.async(execute: {
                   let alert = UIAlertController(title: "Error!", message: "Location services is off", preferredStyle: UIAlertController.Style.alert)
                alert.addAction(UIAlertAction(title: "Go to settings?", style: UIAlertAction.Style.default, handler: { (alert: UIAlertAction!) in
                print("")
                    UIApplication.shared.open(NSURL(string:UIApplication.openSettingsURLString)! as URL)
                    }))
                    self.present(alert, animated: true, completion: nil)
                })
                locationService.requestPermission()
            }
         
    }

    @IBOutlet weak var stopLocationToolBarButton: UIBarButtonItem!
    
    @IBAction func stopLocationToolBarButtonAction(_ sender: UIBarButtonItem) {
        
        locationService.stop()
         
    }
    
    // *** View Controller Functions *** //
    
    deinit {
        print("Deinit: VC NO MEMORY LEAKS")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        locationService.requestPermission()
        
    }
    
    override func viewDidDisappear(_ animated: Bool) {

    }
    
    override func viewWillAppear(_ animated: Bool) {
       
        view.backgroundColor = UIColor.white
    }
    
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    
    }
}

Solution

  • Find a solution. You just had to create a shared instance for the My Location Service class and not create an instance of this class in the ViewController as a variable, but call the same singleton. The reason was that I created different instances of the My Location Service class and started the location in one instance and tried to stop it in another.

    class var sharedInstance: MyLocationService {
        struct Singleton {
            static let instance = MyLocationService()
        }
    
        return Singleton.instance
    }
    

    And call class methods:

    MyLocationService.sharedInstance.start()