I have a simple goal of my app that is get the current coordinate, and use them to add an annotation on the mapview.
I have been tried lots of solution from google results, but its still not working....
The debug area never shows "locationManager did UpdateLocation", the message what I print in function....
It's seems like the app never run "did UpdateLocation" function, even startUpdatingLocation() has been called?
Add location privacy string in info.plist : Done.
Turn on the GPS on my Mac Pro : Done.
Xcode version : 10.1
MacOS : 10.13.6 (High Sierra)
let cloaction = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
MapView.delegate = self
MapView.showsScale = true
MapView.showsPointsOfInterest = true
MapView.showsUserLocation = true
cloaction.requestAlwaysAuthorization()
cloaction.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
print("IN")
cloaction.delegate = self
cloaction.desiredAccuracy = kCLLocationAccuracyBest
cloaction.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
print("locationManager did UpdateLocation")
let location = CLLocationCoordinate2D(latitude: (locations.first?.coordinate.latitude)!, longitude: (locations.first?.coordinate.longitude)!)
currentLat = (locations.first?.coordinate.latitude)!
currentLon = (locations.first?.coordinate.longitude)!
let span = MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)
MapView.setRegion(MKCoordinateRegion(center: CLLocationCoordinate2DMake(currentLat,currentLon), span: span), animated: true)
MapView.showsUserLocation = true
print(locations.first?.coordinate.latitude)
print(locations.first?.coordinate.longitude)
}
Actually the reason is very simple: You call the didUpdateLocation mehthod wich is only called when you change your location. Your Mac is on certain place and dont move so thats why it is not working.
Have you import CoreLocation?
Start with making a variable let myLocation = CLLocation()
Instead of have so much in viewDidLoad you can make a function and call the mLocation in viewDidLoad instead :
func mLocation(){
cloaction.delegate = self
cloaction.desiredAccuracy = kCLLocationAccuracyBest
cloaction.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled(){
cloaction.startUpdatingLocation()
}
}
And thats all you need for the clocation
LocationManager could also be updated
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations:[CLLocation]){
let newLocation = locations[0]
print("\(myLocation.coordinate.latitude)")
print("\(myLocation.coordinate.longitude)")
}
Yes! finally... thank your answering, it's really need to run on device, thanks Kosuke Ogawa's suggestion, and every one's guide, I am a new to learn swift, and first time ask question here, it's fun, thank you every one.
(But I don't know how to accept a answer if the answer is a comment? Someone teach me how do that?)
Related
I am working on construction project and for that I want to fetch exact current location which must satisfy the accuracy withing the 1 meter. I am using google maps with SDK "CLLocationManager" and I am getting the current location but the location is not exact, it has some (+/-)5 meters to (+/-)10 meters error in location. I want the exact/accurate current location which should not exceeds the location accuracy error more than a feet.
Please help me out to fetch EXACT CURRENT LOCATION.
Also, is there any third party library, any hardware device (which I can connect to iOS device.) or anything else, please let me know.
Your valuable comment will be most appreciate.
Edited:-
Here I am sharing my code to get the current location using CLLocationManager:
override func viewDidLoad()
{
super.viewDidLoad()
self.locationManager = CLLocationManager()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.requestAlwaysAuthorization()
self.locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let position = CLLocationCoordinate2D(latitude: manager.location!.coordinate.latitude, longitude: manager.location!.coordinate.longitude)
marker.position = position
print("position:",position)
}
Thank you..
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
guard let location = manager.location else{
return
}
var currentLocationCoordinate = location.coordinate
}
using this delegate function you will get the current location
You can use external gps if you want to get the exact location, with the help of device you will always get this fluctuation. You can also set your location accuracy to best.
https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/LocationBestPractices.html
You should always relay on GPS for accurate location. You can set locationManager.desireAccuracy = kCLLocationAccuracyBest. It will call you locationManager didUpdateLocation with the location array with each location having its accuracy you can apply your logic here.
Be alert to call locationManager.stopUpdatingLocation() when you done with desire accuracy location.
e.g
let horizontalAccuracy: Double = 20.0
let howRecent = location.timestamp.timeIntervalSinceNow
guard CLLocationCoordinate2DIsValid(location.coordinate),
location.horizontalAccuracy > 0,
location.horizontalAccuracy < horizontalAccuracy,
abs(howRecent) < 10 else { return false }
return true
}
When the app is in the foreground, the location updates every second and works perfectly, which is what I want. But when the app is in the background (or in suspended state, I'm not sure), I do not get any local notifications(Ive tested the local notifications on the phone alone, so this isn't the problem). I use local notifications to tell me if the location has been updated, which is how I know the location isn't being updated.
I've set up the background capabilities and info.plist i.e "Privacy - Location When in Use Usage Description" etc. And I've added the below commands.
All my code is in view controllers, not appdelegate, is this my problem?
Note: this works in the background on simulator and on a real device when the device is linked to a laptop with Xcode, and the app is launched from Xcode. It does not work on a real device by itself.
class ViewController: UIViewController, CLLocationManagerDelegate{
let manager = CLLocationManager()
#IBOutlet weak var map: MKMapView!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01,0.01) //shows the size of map screen
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude,location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
map.setRegion(region, animated: true)
self.map.showsUserLocation = true
print("Location Updated")
}
override func viewDidLoad() {
super.viewDidLoad()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
manager.delegate = self
manager.allowsBackgroundLocationUpdates = true
manager.pausesLocationUpdatesAutomatically = false
}
}
Can someone please help? This is one of the last issues I need to solve for one of my projects. Any links or working Github projects would be greatly appreciated! I just cant figure this one out!
I am developing a screen that will need to update location every 10 minutes using a timer. Other than that It only needs to update location at first load and when the view appears to the user again. It should stop monitoring once the the user goes to another view.
I have a code that is supposed to do this, but the issue is that the didUpdateLocations method is not called at any point. Also the map does not show the current location (I use simulated locations).
I have correctly set up the permissions and the app worked fine when it was setup to just show the location. I need to do this to reduce battery consumption.
Here is my related code:
In viewDidLoad:
if #available(iOS 8.0, *) {
self.locationManager.requestAlwaysAuthorization()
}
self.locationManager.allowsBackgroundLocationUpdates = true
self.locationManager.distanceFilter = 1000
self.locationManager.activityType = CLActivityType.automotiveNavigation
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.pausesLocationUpdatesAutomatically = false
self.locationManager.startUpdatingLocation()
self.map.showsUserLocation = true
In viewWillAppear:
self.map.showsUserLocation = true
self.locationManager.startUpdatingLocation()
In viewWillDisappear:
self.map.showsUserLocation = false
self.locationManager.stopUpdatingLocation()
In didUpdateLocations: (at last line)
self.locationManager.stopUpdatingLocation()
Timer Function: (this gets called fine)
Timer.scheduledTimer(timeInterval: 600.0, target: self, selector: #selector(HomePageViewController.updateLocationFromTimer), userInfo: nil, repeats: true)
#objc func updateLocationFromTimer()
{
self.locationManager.startUpdatingLocation()
}
I also tried to catch any error with the following code:
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error.localizedDescription)
}
but it did not get called.
I would love to know why the location is not being updated and why the map is not showing the location. Please help.
Make sure you assign the delegate:
self.locationManager.delegate = self
I did not work for me either and discovered that the place at which you set the delegate impacts this.
E.g. this did not work:
var locationManager = CLLocationManager() {
didSet {
locationManager.delegate = self
}
}
Setting it at a later moment did work as expected. Not sure why to be honest, but maybe this helps someone.
I am new to Swift (and this website, so sorry if I am doing anything wrong), and I am trying to make a running app that tracks the user's location. While the function I used to track the distance works, it doesn't start at 0. When I hit the start button, the distance starts at a random number and then it starts tracking from there.
My question is: Is there something I am not addressing something correctly? If so, is there a way to fix it so that the tracking is more accurate? Here is what I have so far:
override func viewDidLoad() {
super.viewDidLoad()
stopwatchLabel.text = "00:00.00"
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.activityType = .fitness
locationManager.distanceFilter = 10.0
mapView.showsUserLocation = true
startLocation = nil
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Location Delegate Methods
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.002, longitudeDelta: 0.002))
self.mapView.setRegion(region, animated: true)
if startLocation == nil {
startLocation = locations.first
}
var distance = startLocation.distance(from: location!)
let lastDistance = location?.distance(from: location!)
distance += lastDistance!
distanceString = "\(distance)"
distanceLabel.text = distanceString
}
Here is what the app looks like:
the run screen
I realize that other people have asked similar questions, but the questions either have no answer, or they are in a different language (such as Objective-C). If this question has been answered before and I'm just overlooking it, could someone please link the answer to me? Thank you!
When the location manager starts, the first location returned is the cached, last know location. You need to check for this, via the timestamp, as well as check for the level of accuracy that is returned. Something like this in your didUpdateLocations delegate:
let newLocation = locations.last
let timeDiff = newLocation?.timestamp.timeIntervalSinceNow
let accuracyNeeded:CLLocationAccuracy=100.0
if timeDiff < 5.0 && (newLocation?.horizontalAccuracy)!<=accuracyNeeded{
//your code here
}
You have to allow the sensors time to warm up.
Here is a typical didUpdateLocations implementation. We keep track of both the time elapsed since we started updating locations and the improving horizontal accuracy as the sensors warm up. If the horizontal accuracy doesn't improve in a reasonable time, we give up.
You will need a nil property, a Date?, called startTime, and constants REQ_TIME and REQ_ACC. self.stopTrying() turns off updates and resets startTime to nil.
let loc = locations.last!
let acc = loc.horizontalAccuracy
let time = loc.timestamp
let coord = loc.coordinate
if self.startTime == nil { // Date? property, keep track of time
self.startTime = Date()
return // ignore first attempt
}
let elapsed = time.timeIntervalSince(self.startTime)
if elapsed > REQ_TIME { // required time before giving up
self.stopTrying()
return
}
if acc < 0 || acc > REQ_ACC { // desired accuracy
return // wait for the next one
}
// got it
print("You are at \(coord.latitude) \(coord.longitude)")
Im trying to make the map automatically follow the user (location) but somehow the app either it crashes (no error message) or the map doesn't show up when I start up the app. What have I done wrong?
I have tried without the locationManager func, and then it does work. Are there any other ways to follow the user?
class GMSTestViewController: BaseViewController, GMSMapViewDelegate {
#IBOutlet weak var mapView: GMSMapView!
let locationManager = CLLocationManager()
var manager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
//Setup Location Manager
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBestForNavigation
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
//Map type
mapView.mapType = kGMSTypeTerrain
}
override func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation = locations.last
let center = CLLocationCoordinate2D(latitude: userLocation!.coordinate.latitude, longitude: userLocation!.coordinate.longitude)
let camera = GMSCameraPosition.cameraWithLatitude(userLocation!.coordinate.latitude,
longitude: userLocation!.coordinate.longitude, zoom: 8)
let mapView = GMSMapView.mapWithFrame(.zero, camera: camera)
mapView.myLocationEnabled = true
self.view = mapView
let marker = GMSMarker()
marker.position = center
marker.title = "Current Location"
marker.snippet = "XXX"
marker.map = mapView
locationManager.stopUpdatingLocation()
}
}
It looks like this when I start it up, and then it keeps blinking with the map (on the users location).
Check for these things :-
You have set the delegate of your GMSMapview #IBOutlet to self
mapView.delegate = self
You have updated your info.plist file with specific key's
You have a proper internet connection.
You have configured Google Maps in your AppDelegate
var googleApiKey = String(_yourAPIkey)
GMSServices.provideAPIKey(googleApiKey)
I believe the best way to do it is to use key-value observing (KVO):
override func viewWillAppear(animated: Bool) {
mapView.addObserver(self, forKeyPath: "myLocation", options:0, context:nil)
}
deinit {
mapView.removeObserver(self, forKeyPath:"myLocation", context:0)
}
override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
if(keyPath! == "myLocation"]) {
let location = [object myLocation]
let target =
CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude);
mapView.animateToLocation(target)
mapView.animateToZoom(17)
}
}
It seems that google map is not appear in your view.I think you want to get view like in image.
So i suggest you to download Google map SDK version below 1.10 because I am facing this problem too many times.
I suggest you to download google map SDK 1.9.1 for google map from below link
https://developers.google.com/maps/documentation/ios-sdk/releases
Just try to use version 1.9.1 once. Hope this thing works
NOTE: If you want to use Google map's place auto complete and other new services then use higher versions of Google map SDK
Had the same problem.
Fixed by getting new API Key.
As I discovered, you need two keys: one for Google Places, one for Google Maps. At least for testing purpose.
In Google docs it doesn't mention.