Search code examples
iosdelegatesswift3cllocationmanageruistoryboardsegue

Pausing segue until location access is granted/denied


I have a class for managing location tracking (CLLocationManagerDelegate) and a separate class for my vc (UIViewController). I am initiating an instance of my location class within the VC. When the class is initiated, location authorization is requested and once that is accepted or declined I want to segue to another VC to continue the permission requests for the app (notifications).

Right now, the request toaster pops up and the UI segues to the next VC in the background before Accept or Deny is selected.

Any suggestions on how to access the my location class's delegate - locationManager(_:didChangeAuthorization) func from my VC class, or a better idea on how to accomplish this??

The idea is not to have the VC class become a CLLocationManagerDelegate.'

My Location Class:

class MyLocation: NSObject, CLLocationManagerDelegate {

    static let sharedManager = MyLocation()

    var locationManager = CLLocationManager()
    var allDelegates = NSHashTable<CLLocationManagerDelegate>.weakObjects()

    ....
    ....


    func performOnDelegates(_ aBlock:(CLLocationManagerDelegate) -> ()) {

        let hashTable = isObservingHighPrecisionLocationUpdates ? highPrecisionDelegates : allDelegates
        let locationManagerDelegates = hashTable.allObjects

        for aDelegate in locationManagerDelegates {
            aBlock(aDelegate)
        }
    }

    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {    

        print("LOCATION SERVICES: Re-evaluating state after authorization state changed")
        performOnDelegates { $0.locationManager?(manager, didChangeAuthorization: status) }
    }

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

        performOnDelegates { $0.locationManager?(manager, didUpdateLocations: locations) }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

        print("WARNING: Location update failed with error = \(error)")
        performOnDelegates { $0.locationManager?(manager, didFailWithError: error) }
    }
}

My View Controller Class:

import UIKit

class MyViewController: UIViewController, CLLocationManagerDelegate {

    override func viewDidLoad() {
        super.viewDidLoad()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    @IBAction func didTapNext(_ sender: UIButton) {
        if sender.restorationIdentifier == "locationAccessButton" {
        MyLocation.sharedManager.locationManager.requestWhenInUseAuthorization()
            performSegue(withIdentifier: "nextPermissionSegue", sender: nil)
        }
    }
}

}


Solution

  • Don't perform the segue right away.

    Don't reach into your MyLocation class and send messages to the location manager directly. Instead, add a new function to your MyLocation class to request authorization, and have that function take a completion block. Have the completion block take a status parameter (request authorized, request denied, etc).

    Call that function, and do the performSegue in the completion block.