Location coordinates are not nill yet labels don't get updated when app is loaded but get loaded if I come back from another screen tho - ios

I have defined a global variable to store location coordinates and im updating location in Appdelegate as soon as the app launches. Here's the code for that:
var locationManager:CLLocationManager!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
window = UIWindow(frame: UIScreen.main.bounds)
determineCurrentLocation()
self.pushToHomeScreen()
return true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if GlobalUserManager.shared.currentLocation == nil {
GlobalUserManager.shared.currentLocation = locations.last
locationManager.stopUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error - locationManager: \(error.localizedDescription)")
}
//MARK:- Intance Methods
func determineCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
After this the Home Screen opens where I have two labels to show location data. It didn't get update when Homescreen is loaded for both cases when I tried to update by putting code in viewdidLoad() and viewWillAppear(). So I tried putting code in viewDidAppear() and its something like this:
override func viewDidAppear(_ animated: Bool) {
if GlobalUserManager.shared.currentLocation != nil {
lblLat.text = GlobalUserManager.shared.currentLocation.latitude
lblLong.text = GlobalUserManager.shared.currentLocation.longitude
}
else {
lblLat.text = "Lat not available"
lblLong.text = "Long not available"
}
}
When screen is loaded, labels are empty which means at least GlobalUserManager.shared.currentLocation != nil but I want them to get updated as soon as screen is loaded. Instead I have to click another page and come back and then they are updated.

Related

Retrieving the current location of the user/ retrieving the values of longitude and latitude watchkit/ios swift

I want to obtain the current location (longitude and latitude) of the user, but I just get 0 for both of the variables. I do not know where the problem lies in. I am following this tutorial and have updated the infop.list of the app folder and the watch extension folder (NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription), inserted the needed Watchconnector to both of the folders with cocoapods, and I also have added the Corelocation framework via link binary with libraries.
I have little knowledge about swift and watch os, I hope anyone can help.
Here is the project file: https://ufile.io/l5elkpsw
Thank you very much.
And here are my Appdelegate and Interfacecontroller file:
import UIKit
import CoreLocation
import MapKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, CLLocationManagerDelegate {
let locationManager:CLLocationManager = CLLocationManager()
var currentLocation = CLLocation()
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
WatchConnector.shared.activateSession()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestLocation()
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
return true
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locations.count == 0
{
return
}
self.currentLocation = locations.first!
let message = ["lat":self.currentLocation.coordinate.latitude,"long":self.currentLocation.coordinate.longitude]
WatchConnector.shared.sendMessage(message, withIdentifier: "sendCurrentLocation") { (error) in
print("error in send message to watch\(error.localizedDescription)")
}
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Fail to load location")
print(error.localizedDescription)
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
import WatchKit
import Foundation
import CoreLocation
class InterfaceController: WKInterfaceController{
private let locationAccessUnauthorizedMessage = "Locations Disabled\n\nEnable locations for this app via the Settings in your iPhone to see meetups near you!"
private let pendingAccessMessage = "Grant location access to GPS dummy"
#IBOutlet weak var map: WKInterfaceMap!
#IBOutlet weak var button: WKInterfaceButton!
#IBOutlet weak var latitudeL: WKInterfaceLabel!
#IBOutlet weak var longitudeL: WKInterfaceLabel!
#IBOutlet weak var authorizeL: WKInterfaceLabel!
var currentLocation = CLLocation()
let locationManager = CLLocationManager()
var lat: Double = 0.0
var long: Double = 0.0
override func awake(withContext context: Any?) {
super.awake(withContext: context)
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
// Configure interface objects here.
}
override func willActivate() {
// This method is called when watch view controller is about to be visible to user
super.willActivate()
WatchConnector.shared.listenToMessageBlock({ (message) in
self.lat = message["lat"] as! Double
self.long = message["long"] as! Double
print(self.lat)
print(self.long)
self.currentLocation = CLLocation(latitude: self.lat as! CLLocationDegrees, longitude: self.long as! CLLocationDegrees)
let mylocation : CLLocationCoordinate2D = CLLocationCoordinate2DMake(self.currentLocation.coordinate.latitude, self.currentLocation.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: mylocation, span: span)
self.map.setRegion(region)
self.map.addAnnotation(mylocation, with: .red)
}, withIdentifier: "sendCurrentLocation")
let authorizationStatus = CLLocationManager.authorizationStatus()
handleLocationServicesAuthorizationStatus(authorizationStatus)
}
func handleLocationServicesAuthorizationStatus(_ status: CLAuthorizationStatus) {
switch status {
case .notDetermined:
print("handleLocationServicesAuthorizationStatus: .undetermined")
handleLocationServicesStateNotDetermined()
case .restricted, .denied:
print("handleLocationServicesAuthorizationStatus: .restricted, .denied")
handleLocationServicesStateUnavailable()
case .authorizedAlways, .authorizedWhenInUse:
print("handleLocationServicesAuthorizationStatus: .authorizedAlways, .authorizedWhenInUse")
handleLocationServicesStateAvailable(status)
}
}
func handleLocationServicesStateNotDetermined() {
authorizeL.setText(pendingAccessMessage)
locationManager.requestWhenInUseAuthorization()
}
func handleLocationServicesStateUnavailable() {
authorizeL.setText(locationAccessUnauthorizedMessage)
}
func handleLocationServicesStateAvailable(_ status: CLAuthorizationStatus) {
switch status {
case .authorizedAlways:
locationManager.startUpdatingLocation()
case .authorizedWhenInUse:
locationManager.requestLocation()
default:
break
}
}
override func didDeactivate() {
// This method is called when watch view controller is no longer visible
super.didDeactivate()
}
#IBAction func btnPressed() {
self.latitudeL.setText("\(self.lat)")
self.longitudeL.setText("\(self.long)")
print("\(locationManager.requestLocation())")
print("\(self.lat)")
print("\(self.long)")
}
}
extension InterfaceController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("error:: \(error.localizedDescription)")
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == .authorizedWhenInUse {
locationManager.requestLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if locations.first != nil {
print("location:: (location)")
}
}
}
Are you testing on a simulator? If so, you might need to set the location to something in the Debug/Location menu:

Send Location of User in Background Swift

I am building an app where the user clicks a button and for 60mins (or any amount of time) we keep track of them by uploading their location to a server. Currently we are using 'Did Update Locations' function to send the users location to firebase in real-time.
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
This system works but it spams the server sending the location of the user to the server once every second.
This is too much data and we would only need to send the users location to the server once every 10-30 seconds.
What can we do send the users location once every 10-30 seconds?
class ViewController: UIViewController, CLLocationManagerDelegate {
private var locman = CLLocationManager()
private var startTime: Date? //An instance variable, will be used as a previous location time.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let loc = locations.last else { return }
let time = loc.timestamp
guard var startTime = startTime else {
self.startTime = time // Saving time of first location, so we could use it to compare later with second location time.
return //Returning from this function, as at this moment we don't have second location.
}
let elapsed = time.timeIntervalSince(startTime) // Calculating time interval between first and second (previously saved) locations timestamps.
if elapsed > 30 { //If time interval is more than 30 seconds
print("Upload updated location to server")
updateUser(location: loc) //user function which uploads user location or coordinate to server.
startTime = time //Changing our timestamp of previous location to timestamp of location we already uploaded.
}
}
import UIKit
import CoreLocation
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate,CLLocationManagerDelegate {
var window: UIWindow?
var locationManager = CLLocationManager()
var backgroundUpdateTask: UIBackgroundTaskIdentifier!
var bgtimer = Timer()
var latitude: Double = 0.0
var longitude: Double = 0.0
var current_time = NSDate().timeIntervalSince1970
var timer = Timer()
var f = 0
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
self.doBackgroundTask()
return true
}
func applicationWillResignActive(_ application: UIApplication) {
}
func applicationWillEnterForeground(_ application: UIApplication) {
print("Entering foreBackground")
}
func applicationDidBecomeActive(_ application: UIApplication) {
}
func applicationWillTerminate(_ application: UIApplication) {
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("Entering Background")
// self.doBackgroundTask()
}
func doBackgroundTask() {
DispatchQueue.main.async {
self.beginBackgroundUpdateTask()
self.StartupdateLocation()
self.bgtimer = Timer.scheduledTimer(timeInterval:-1, target: self, selector: #selector(AppDelegate.bgtimer(_:)), userInfo: nil, repeats: true)
RunLoop.current.add(self.bgtimer, forMode: RunLoopMode.defaultRunLoopMode)
RunLoop.current.run()
self.endBackgroundUpdateTask()
}
}
func beginBackgroundUpdateTask() {
self.backgroundUpdateTask = UIApplication.shared.beginBackgroundTask(expirationHandler: {
self.endBackgroundUpdateTask()
})
}
func endBackgroundUpdateTask() {
UIApplication.shared.endBackgroundTask(self.backgroundUpdateTask)
self.backgroundUpdateTask = UIBackgroundTaskInvalid
}
func StartupdateLocation() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestAlwaysAuthorization()
locationManager.allowsBackgroundLocationUpdates = true
locationManager.pausesLocationUpdatesAutomatically = false
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print("Error while requesting new coordinates")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
self.latitude = locValue.latitude
self.longitude = locValue.longitude
f+=1
print("New Coordinates: \(f) ")
print(self.latitude)
print(self.longitude)
}
#objc func bgtimer(_ timer:Timer!){
sleep(2)
/* if UIApplication.shared.applicationState == .active {
timer.invalidate()
}*/
self.updateLocation()
}
func updateLocation() {
self.locationManager.startUpdatingLocation()
self.locationManager.stopUpdatingLocation()
}}
I added the sleep function to delay of calling the location and send the information to server
Since this is running in both the app is active and goes to background. If you want only background process, remove or comment the function self.doBackgroundTask() from didFinishLaunchingWithOptions and remove the comment for self.doBackgroundTask() in the applicationdidEnterBackground. And then remove the comment in the function bgtimer(), since the background process has to stop once the app comes to active state.
Apps normally get suspended (no longer get CPU time) a moment after being moved to the background. You can ask for extra background time, but the system only gives you 3 minutes.
Only a very limited class of apps are allowed to run in the background for longer than that. Mapping/GPS applications are one of those categories. However, your app is not a mapping/GPS application, so I doubt if Apple would approve it.
Bottom line: I think you might be out of luck running your location queries for more than 3 minutes.
EDIT:
As Paulw11 points out, you can use the significant location change service to get location updates when the device moves by large distances.

didUpdateLocations never called

I'm trying to get the user's location. To do so I have set the following property in the info.plist :
I have also added the following code in my viewDidLoad method as well as the function below. The problem is that the locationManager(manager, didUpdate....) function never gets called, I also never get prompted for permission to access location, even though I have removed and installed the app again. I am testing this on my iPad, not on the simulator. The didFailWithError function never gets called either.
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("UPDATING")
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
let latitude = locValue.latitude
let longitude = locValue.longitude
latitudeText = "\(latitude)"
longitudeText = "\(longitude)"
if let a = latitudeText, b = longitudeText {
print(a)
print(b)
self.locationManager.stopUpdatingLocation()
if (userAlreadyExist()) {
dispatch_async(dispatch_get_main_queue(), {
//self.performSegueWithIdentifier("segueWhenLoggedIn", sender: self)
self.performSegueWithIdentifier("showCamera", sender: self)
// self.performSegueWithIdentifier("showTabBarController", sender: self)
})
}
else {
dispatch_async(dispatch_get_main_queue(), {
self.performSegueWithIdentifier("segueWhenLoggedOut", sender: self)
})
}
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print(error.localizedDescription)
}
EDIT :
I have added the following snippet of code :
if CLLocationManager.locationServicesEnabled() {
print("yes")
}
else {
print("no")
}
it returns yes. I have also checked on my device, locationServices are enabled, the app is listed there, however all the other apps have "While Using", "Never" or "Always" written next to them, mine doesn't have anything written.
where do you start the location update ? for example:
//location manager
lazy var locationManager: CLLocationManager = {
var _locationManager = CLLocationManager()
_locationManager.delegate = self
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
_locationManager.activityType = . automotiveNavigation
_locationManager.distanceFilter = 10.0 // Movement threshold for new events
_locationManager.allowsBackgroundLocationUpdates = true // allow in background
return _locationManager
}()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation() // start location manager
}
here is a working conroller code:
also important to to set up Custom iOS Target Properties.
Add these two lines to the Info.plist:
NSLocationWhenInUseUsageDescription
NSLocationAlwaysUsageDescription
//
// ViewController.swift
// LocationTest2
import UIKit
import CoreLocation
class ViewController: UIViewController {
//location manager
lazy var locationManager: CLLocationManager = {
var _locationManager = CLLocationManager()
_locationManager.delegate = self
_locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
_locationManager.activityType = . automotiveNavigation
_locationManager.distanceFilter = 10.0 // Movement threshold for new events
// _locationManager.allowsBackgroundLocationUpdates = true // allow in background
return _locationManager
}()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
//allow location use
locationManager.requestAlwaysAuthorization()
print("did load")
print(locationManager)
//get current user location for startup
// if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
// }
}
}
// MARK: - CLLocationManagerDelegate
extension ViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
for location in locations {
print("**********************")
print("Long \(location.coordinate.longitude)")
print("Lati \(location.coordinate.latitude)")
print("Alt \(location.altitude)")
print("Sped \(location.speed)")
print("Accu \(location.horizontalAccuracy)")
print("**********************")
}
}
}
for me worked:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locationManager update")
}
instead of this
private func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locationManager update")
}
Also make sure you have set the custom location to simulator as by default it will be None ...
In the simulator go to Debug -> Location-> .
It should also be noted that locationManager:didFailWithError: will run if the location is not set in the simulator, as you'd expect.
A very subtle cause for this bug in Swift code. Don't define the delegate call didUpdateLocations as private or fileprivate. The location manager won't be able to find or call it if you do.
Good:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
Bad:
fileprivate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
}
I looked for answers high and low. This is the only thing that worked for me:
Change the func for didUpdateToLocation to:
func locationManager(_: CLLocationManager, didUpdateToLocation newLocation: CLLocation!,fromLocation oldLocation: CLLocation!) {
}
Note the subtle change of "as _: CLLocationManager", instead of "manager: CLLocationManager".
You should call startUpdatingLocation() inside the didDetermineState delegate method
if CLLocationManager.authorizationStatus() != .authorizedWhenInUse {
locationManager.requestWhenInUseAuthorization()
}else{
locationManager.startUpdatingLocation()
}
//later
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .authorizedWhenInUse:
manager.startUpdatingLocation()
break
case .authorizedAlways:
manager.startUpdatingLocation()
break
case .denied:
//handle denied
break
case .notDetermined:
manager.requestWhenInUseAuthorization()
break
default:
break
}
}
I was using AppDelegate as CLLocationManagerDelegate instead of ViewController like in most examples, this was the code I had
// AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var locationManager: CLLocationManager?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
self.locationManager = CLLocationManager()
self.locationManager?.delegate = self
return true
}
}
and I was trying to get updates when exit event was called
// AppDelegate.swift
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
if !CLLocationManager.locationServicesEnabled() {
return
}
let locationManager = CLLocationManager()
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.allowsBackgroundLocationUpdates = true
locationManager.startUpdatingLocation()
return
}
}
But this didn't work. Instead I had to move the configuration of locationManager to AppDelegate class, and only start the updates in AppDelegate extension.
Like this
// AppDelegate.swift
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var locationManager: CLLocationManager?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
self.locationManager = CLLocationManager()
self.locationManager?.delegate = self
/* This was the catch, it needs to be here instead of inside extension */
self.locationManager?.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager?.distanceFilter = kCLDistanceFilterNone
self.locationManager?.allowsBackgroundLocationUpdates = true
/* */
return true
}
}
extension AppDelegate: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
if !CLLocationManager.locationServicesEnabled() {
return
}
/* Only do this here */
manager.startUpdatingLocation()
return
}
}
Then it started working, and sending continuous location updates. Also I tested on simulator.
Make sure the startUpdatingLocation method gets called on the main thread, like so:
DispatchQueue.main.async { [weak self] in
self?.locationManager.startUpdatingLocation()
}

mapView.showsUserLocation = true affects the correctness of gps in my swift app. Why?

In my app I want to know user's real location. I want to show it in couple places as a plain text (as a string of longitude/latitude) and also show it on the map. I have several ui view controllers and one of them contains - now, for testing - a print to the console with current longitude and latitude, it also contains a map view.
I'm fetching the current gps position from my app delegate and put it on the screen.
In my AppDelegate.swift class I have:
var locationManager: CLLocationManager! = nil
var location: CLLocation! = nil
var longitude : Double = 0
var latitude : Double = 0
var location_fixed = false
func application(application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
initLocationManager()
}
func initLocationManager() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if CLLocationManager.authorizationStatus() == .AuthorizedAlways {
locationManager!.startUpdatingLocation()
} else {
locationManager!.requestAlwaysAuthorization()
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Failed to initialize GPS: ", error.description)
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
location = locations.first!
print("Managed to get a fix on location")
let coord = location.coordinate
longitude = coord.longitude
latitude = coord.latitude
location_fixed = true;
locationManager.stopUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
switch status {
case .NotDetermined:
print("NotDetermined")
case .Restricted:
print("Restricted")
case .Denied:
print("Denied")
case .AuthorizedAlways:
print("AuthorizedAlways")
locationManager!.startUpdatingLocation()
case .AuthorizedWhenInUse:
print("AuthorizedWhenInUse")
locationManager!.startUpdatingLocation()
}
}
func stopGPS() -> Void
{
print("STOP GPS")
location_fixed = false;
locationManager.stopUpdatingLocation()
}
func startGPS() -> Void
{
locationManager.startUpdatingLocation()
}
func isLocationFixed() -> Bool
{
return self.location_fixed
}
func getLongitude() -> Double
{
return self.longitude
}
func getLatitude() -> Double
{
return self.latitude
}
func getLocation() -> CLLocation
{
return self.location
}
Now in my UIViewController in viewWillAppear method I added asynchronous call to the app delegate methods for checking current gps position:
let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT
dispatch_async(dispatch_get_global_queue(priority, 0)) {
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.startGPS()
while (!appDelegate.isLocationFixed())
{
sleep(1)
}
dispatch_async(dispatch_get_main_queue()) {
self.fetchRequests(self.radius, lat: appDelegate.getLatitude(), lon: appDelegate.getLongitude())
print("gps here: \(appDelegate.getLatitude()), \(appDelegate.getLongitude())") }
}
and now when I enter this panel and waits for fetching the gps - I see the correct data. So far so good. Now, when I change the gps position in a simulator, then go to some other panel and come back to this one - I see the new data, which is fine.
And now comes the real weird problem. In the same panel I have a map view.
It's embedded in a UIViewController that I put in a container, so I cannot access it from my async call. It has a viewDidLoad() method and when I put there:
mapView.showsUserLocation = true
and run the app, I see the blue dot exactly when the simulator's gps points out, but now my data in the previous async call is not updating correctly.
When I comment out that one particular line of code, I'm getting the correct data shown as gps here:. When I leave it as a part of the code, then this line gps here: shows the same data all the time, even though I'm changing the gps position in a simulator, leaving and entering the panel several times. What's up with that?

Swift: Google Map code throwing nil exception

I have the following code and it should basically detect location (if location services are on), then goes back to previous page and shows the coordinates (when button clicked).
#IBOutlet var mapView:GMSMapView!// Adding Google Map check on Storyboard
var locationManager: CLLocationManager!
var viewController : ViewController! //to save the object of previous controller to send the location back
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
locationManager = CLLocationManager() // Intialize the location manager
locationManager.delegate = self
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
//Methos to change the MApType
#IBAction func changeMaptoEarthView()
{
self.mapView.mapType = kGMSTypeSatellite
}
#IBAction func changeMaptoMapView()
{
self.mapView.mapType = kGMSTypeNormal
}
//Method to get UserLocation
#IBAction func sendLocationtoPreviousView()
{
viewController.locationRecieved(locationManager.location)
self.performSegueWithIdentifier("backSegue", sender: nil)
}
#IBAction func addUserLocation() //Detect location click event
{
if(CLLocationManager.authorizationStatus() == .AuthorizedWhenInUse) // If already have location access
{
locationManager.startUpdatingLocation()
}
else if (CLLocationManager.authorizationStatus() == .Denied)// If location access is denied in setting
{
UIAlertView(title: "Permission", message: "Please allow location services in setting", delegate: nil, cancelButtonTitle: "ok").show()
}
else
{
locationManager.requestWhenInUseAuthorization() // Ask user permission if permission not given
}
}
//CLLocation Manager Delegate methoda
func locationManager(manager: CLLocationManager!, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse {
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
if let location = locations.first as? CLLocation {
self.mapView.clear() // clear all overlay on Map
self.mapView.camera = GMSCameraPosition(target: location.coordinate, zoom: 15, bearing: 0, viewingAngle: 0)
// Adding pin on Current location
var marker = GMSMarker()
marker.position = location.coordinate
marker.snippet = "My Location"
marker.appearAnimation = kGMSMarkerAnimationPop
marker.map = mapView
locationManager.stopUpdatingLocation()
}
}
The app works in simulator until I say go back, then it throws nil error message on this line:
viewController.locationRecieved(locationManager.location)
What could be the reason? I can see the pin on the map although the map is not showing any graphics except google logo below
If you don't see the map graphic in your view (subclass of GMSMapView), this is because of the Google map API key , maybe you have not set it yet in your app delegate or its not set correctly !
make sure you have set the correct google API key with you app bundle id and your account in google . you have to set below code in your app delete , did didFinishLaunchingWithOptions function :
import GoogleMaps
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
GMSServices.provideAPIKey("your API Key")
}
The location property on CLLocationManager is an Optional - meaning that it can be nil. According to the docs, it will be nil if no location data has ever been retrieved.
You don't show how viewController.locationRecieved is defined, but my guess is that you've configured the CLLocation argument to an implicitly unwrapped optional (i.e., with a "!"). Passing nil to such an argument will cause a crash.

Resources