0

I have two view controllers - one with the mapView that is able to obtain user location coordinations through locationManager, and a second VC that I wish to be able to pull these user coordinates.

First VC: MapView

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
    var coordinatesOfUser = locations.last?.coordinate
    print("The value of usercoordinates are \(coordinatesOfUser)")

    // here I want to be able to pull this variable, coordinatesOfUser


    if let location = locations.last {
        let span = MKCoordinateSpanMake(0.00775, 0.00775)
        let myLocation = CLLocationCoordinate2DMake(location.coordinate.latitude,location.coordinate.longitude)
        let region = MKCoordinateRegionMake(myLocation, span)
        map.setRegion(region, animated: true)
    }
    self.map.showsUserLocation = true
    locationManager.stopUpdatingLocation()


}

Second VC:

I was thinking of calling the locationManager function in this VC. Is this the most efficient way to pull the coordinates to this VC? And if so, how would I go about doing it?

Kevin
  • 1,189
  • 2
  • 17
  • 44
  • It could be easily realized with MVVM pattern http://rasic.info/bindings-generics-swift-and-mvvm/. Use one view model for both view controllers. – Vasilii Muravev Jul 06 '17 at 18:35

2 Answers2

2

Here's a couple options to solve this:

Delegation: Your secondVC could have a delegate that allows the first view controller to get coordinates from it. The advantage here is that you could receive updates as the come in.

protocol MyLocationDelegate: class {
    func newLocationArrived(location: CLLocation)
}

class FirstVC: UIViewController, MyLocationDelegate {

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

    func newLocationArrived(location: CLLocation) {
        print(location)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let dest = segue.destination as? SecondVC {
            dest.delegate = self
        }
    }
}

class SecondVC: UIViewController, CLLocationManagerDelegate {

    /// ... ...

    weak var delegate: MyLocationDelegate?

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

        /// do something with the location

        /// provide the data via delegation
        delegate?.newLocationArrived(location: CLLocation())
    }
}

Notifications: Post a notification via NSNotificationCenter. Also able to receive updates as the come in, just send via notification center instead of through a delegate.

postNotificationName:object:userInfo:

Child View Controller: Depending on whether the second view controller and its view are a child of the first, this could allow direct access. Not always an option.

Singleton (CLLocationManager): If you plan to use Location Services in other places throughout the app, you can move the CLLocationManager into its own class with a Singleton. Other view controllers can reference that class for their specific needs. This can also be helpful when using the background or significant change locations as they might need to use the LaunchOptions Key to restart the location manager.

class MyLocationManager: CLLocationManager, CLLocationManagerDelegate {

    static let shared = MyLocationManager()

    var locations = [CLLocation]()

    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        for location in locations {
            self.locations.append(location)
        }
    }
}
kuhncj
  • 236
  • 2
  • 10
0

I had the same problem and I finally fixed it with a Notification, as kuhncj said.

This is how the code looks like at the end:

    //Get user location
    func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {

            if status == .authorizedWhenInUse {
                locationManager.startUpdatingLocation()

                mapView.isMyLocationEnabled = true
                mapView.settings.myLocationButton = true
            } else {
                initialLocation()
            }
        }

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

            if let location = locations.first {

                mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)

                locationManager.stopUpdatingLocation()

                let userInfo: NSDictionary = ["location": location]

                //Post notification
                NotificationCenter.default.post(name: NSNotification.Name("UserLocationNotification"), object: self, userInfo: userInfo as [NSObject : AnyObject])

            }
        }

And then in the other view controller:

    var userLocation: String?

    override func viewDidLoad() {
            super.viewDidLoad()

            //Observer that receives the notification
            NotificationCenter.default.addObserver(self, selector: #selector(locationUpdateNotification), name: Notification.Name("UserLocationNotification"), object: nil)

        }

        func locationUpdateNotification(notification: NSNotification) {
            if let userInfo = notification.userInfo?["location"] as? CLLocation {
                //Store user location
                self.userLocation = "\(userInfo.coordinate.latitude), \(userInfo.coordinate.longitude)"
            }
        }

Then I was able to use the stored userLocation for another methods.

celiux
  • 613
  • 6
  • 10