I can't get Swift to give me a user's location - swift

I am trying to get the user's location in Swift. Using the code below. But when I call
let currentloc = self.locationManager.location?.coordinate , it returns a nil value. The code below is above the let currentloc line in the script.
self.locationManager.delegate = self
self.locationManager.requestAlwaysAuthorization()
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()

Make sure you:
import Corelocation + import MapKit in your class.
conform to the MKMapViewDelegate and CLLocationManagerDelegate
instantiate the locationmanager: let locationManager = CLLocationManager() in your class variables
in your viewDidLoad try:
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager. requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
Add the following delegate method to print your location:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print(locations.last!.coordinate)
}

TLDR;
Product -> Scheme -> Edit Scheme -> Options -> Allow Location Simulation must be checked and try providing a default location, don't leave it set to "none"
When you test on simulator, you have to provide a default location, please check my answer here : https://stackoverflow.com/a/32887820/4887400

Related

CLLocationManager requestLocation not calling didUpdateLocations

I have a simple CLLocationManager implementation that works in one project but not in my new project.
The code is almost identical but I cannot get the .didUpdateLocations function to call. My code is below. Any ideas why I cannot get the update to work? I'm at a loss, I've build many apps using location services and never seen this situation.
Also I have the three settings in the PLIST set correctly for Privacy-Location Always etc.
There are no errors given, it simply doesn't call .didUpdateLocations
Weather Class
class DarkSkyWeatherController: UIViewController, CLLocationManagerDelegate {
var weatherGetterDelegate: DarkSkyWeatherControllerDelegate?
var locationManager = CLLocationManager()
var lat = String()
var long = String()
func getLocation() {
// Ask for Authorisation from the User.
locationManager.requestAlwaysAuthorization()
// For use in foreground
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
locationManager.startUpdatingLocation()
}
locationManager.delegate = self
locationManager.requestLocation()
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let locValue: CLLocationCoordinate2D = manager.location?.coordinate else {return}
print("locations = \(locValue.latitude) \(locValue.longitude)")
lat = String(locValue.latitude)
long = String(locValue.longitude)
getDarkSkyWeather { (fetchedInfo) in
if let myFetchedInfo = fetchedInfo {
self.weatherGetterDelegate?.getMyWeather(weather: myFetchedInfo)
}
}
}
ViewDidLoad in main window
let weather = DarkSkyWeatherController()
weather.weatherGetterDelegate = self
weather.getLocation()
Thanks for looking at this.
Without seeing your full main window code, I bet that the problem is with the scope and lifecycle of your controller:
override func viewDidLoad() {
let weather = DarkSkyWeatherController()
weather.weatherGetterDelegate = self
weather.getLocation()
// Function exits. The weather constant dies off.
// This is why you don't get callbacks.
}
Do the following, instead.
let weather = DarkSkyWeatherController()
override func viewDidLoad() {
weather.weatherGetterDelegate = self
weather.getLocation()
// Function exits, but the weather constant lives on as a field of your main ViewController. You'll get your callbacks now.
}

DidUpdateLocation not storing location, userLoc always nil

I am trying to simply get the user's current device location and store it in a global variable called userLoc. I have this code to call didUpdateLocation:
self.locationManager.requestLocation()
print("aaa ", self.userLoc)
and this to set the userLoc to the current location:
func locationManager(_ manager: CLLocationManager,
didUpdateLocations locations: [CLLocation]) {
if let location = locations.last {
self.userLoc = location
}
}
userLoc is defined like this:
var userLoc: CLLocation?
but when I run the app and try to print userLoc, it ALWAYS prints:
aaa nil
The Privacy - Location When In Use Usage Description is set in the Info.plist. I honestly dont know what else to try. I've been banging my head against the wall for a while trying to fix this. Any help you could give would be very much appreciate. Thank you.
This is what I do to get user location within my view controller class. I think you are missing locationManager.startUpdatingLocation():
var currentLocation: CLLocationCoordinate2D!
var locationManager: CLLocationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
currentLocation = locationManager.location!.coordinate

After requestAuthorization on first load the rest of viewDidLoad isn't executed and the next line jumps to the delegate functions (swift 3)

My app seems to work fine on each use except the first one.
I ask for user authorization and I have the appropriate keys in the plist but the rest of viewDidLoad after the lines requesting authorization don't execute. I have attached the breakpoints below and breakpoint 2 isn't hit on the first time the app is used.
I'm pretty sure after authorization is given it just jumps to the func locationManager in the extension.
I could wait till the very end to ask for authorization until everything else is set but not sure if this is the best, or only way, out.
Thanks,
class MapController: UIViewController, GMSMapViewDelegate {
var locationManager = CLLocationManager()
var currentLocation: CLLocation?
#IBOutlet var mapView: GMSMapView!
override func viewDidLoad(){
super.viewDidLoad()
locationManager = CLLocationManager()
--------------------------> breakpoint 1
locationManager.requestAlwaysAuthorization()
locationManager.requestWhenInUseAuthorization()
-------------------------> breakpoint 2
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = 50
locationManager.startUpdatingLocation()
locationManager.delegate = self
guard let lat = locationManager.location?.coordinate.latitude else {return}
guard let lng = locationManager.location?.coordinate.longitude else {return}
mapView.settings.compassButton = true
mapView.settings.myLocationButton = true
mapView.isMyLocationEnabled = true
let camera = GMSCameraPosition.camera(withLatitude: lat, longitude: lng, zoom: 1)
mapView.camera = camera
mapView.delegate = self
getData()
}
extension MapController: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location: CLLocation = locations.last else {return}
let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude, longitude: location.coordinate.longitude, zoom: 1)
mapView.animate(to: camera)
}
}
Why do you request authorisation to two different things? If you request and get always authorisation, you don't need to request when in use authorisation, since this is only a subset of always authorisation.
Also, these are both asynchronous functions, so you cannot execute location based code right after them, since if you don't have authorisation yet, the code right after requestAuthorization() will be executed before you actually got authorisation and hence the functions won't be called, since you don't have authorisation yet.
You have to check the authorisation status before calling any location related code, such as locationManager.startUpdatingLocation() and only execute the location related code if the status is authorised. If it is not authorised, you have to implement CLLocationManagerDelegate's locationManager(_:didChangeAuthorization:) function and call the location related call inside that function after checking that the result of the change is an authorised status.

swift - How to delay method call until variables value is stored regarding updating current location

I would like to call a method but it requires coordinates that have not been stored in variables yet.
So far I have:
1) acquired current location
2) Think I store them?
What I want to do:
1) Call method After these variables are stored so the program can run
class ViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
var clLatitude : CLLocationDegrees!
var clLongitude: CLLocationDegrees!
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestAlwaysAuthorization()
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location:CLLocationCoordinate2D = manager.location!.coordinate
//Test printing coordinates to screen
print("locations = \(location.self.clLatitude) \(location.self.clLongitude)")
//place where I think I store the variables?
self.clLatitude = location.latitude
self.clLongitude = location.longitude
}
func methodToBeCalled(){
//to be called after variables are stored.
}
I believe I have covered everything regarding my problem
i think you just need to call the method at the end of locationManager(manager: didUpdateLocations:)
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location:CLLocationCoordinate2D = manager.location!.coordinate
//Test printing coordinates to screen
print("locations = \(location.self.clLatitude) \(location.self.clLongitude)")
//place where I think I store the variables?
self.clLatitude = location.latitude
self.clLongitude = location.longitude
// call method
methodToBeCalled()
}
func methodToBeCalled(){
//to be called after variables are stored.
}

EXC_BAD_INSTRUCTION for Map location App

I'm very new to coding so please forgive me. I'm trying to run a program on my Apple Watch that tells me my location coordinates, altitude, speed, and course.
Everything was working up to my println(userlocationInfo) line, but then I got an error at my let row = table.rowControllerAtIndex(index) as! tableRowController:
Thread 1:EXC_BAD_INSTRUCTION(code=EXC_I386_INVOP,subcode=0x0)
By the way, what exactly does that error message mean? How can I solve an error message like this in the future by myself?
import WatchKit
import Foundation
import CoreLocation
class InterfaceController: WKInterfaceController, CLLocationManagerDelegate {
#IBOutlet weak var table: WKInterfaceTable!
var locationManager = CLLocationManager()
var userLocationInfo = [String]()
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
let locationArray = locations as NSArray
let location = locationArray.lastObject as! CLLocation
userLocationInfo.removeAll(keepCapacity: true)
userLocationInfo.append("\(location.coordinate.latitude)")
userLocationInfo.append("\(location.coordinate.longitude)")
userLocationInfo.append("\(location.altitude)")
userLocationInfo.append("\(location.speed)")
userLocationInfo.append("\(location.course)")
println(userLocationInfo)
table.setNumberOfRows(userLocationInfo.count, withRowType: "tableRowController")
for (index, value) in enumerate(userLocationInfo) {
let row = table.rowControllerAtIndex(index) as! tableRowController
row.tableRowLabel.setText(value)
}
}
override func awakeWithContext(context: AnyObject?) {
super.awakeWithContext(context)
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
You should move your table function out of the didUpdateLocations delegate and call it after you have the location data. The didUpdateLocations will continue to run until you stop updating locations.