I have a view controller that contains a map view and a button that I want to be able to press and update the current location. I am also trying to take that newly updated location (longitude and latitude) and update two columns in a database. I have created a PHP script that I know for a fact works (I've tested it), but I am having trouble combining everything with an IB action. The code below is taken from my viewcontroller.swift file. When I build and run on the simulator, nothing is updated in the database.
let loccationManager = CLLocationManager()
var latitude = 0.0
var longitude = 0.0
#IBAction func updateMap(sender: AnyObject) {
loccationManager.startUpdatingLocation()
print(latitude)
print(longitude)
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
latitude = (location?.coordinate.latitude)!
longitude = (location?.coordinate.longitude)!
}
Related
I have the following code
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
var coordinates: String?
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//updates the user's location as the user moves
let location: CLLocation = locations[0] as CLLocation
coordinates = "\(location.coordinate.latitude),\(location.coordinate.longitude)"
print(coordinates!)
}
When I run this on the simulator, the program works fine but it doesn't print the coordinates. When I run it on my iPhone, it prints the coordinates. Is there something in the Xcode settings I need to change to fix this? Also, when I try to use the "coordinates" variable in another function, I get an error saying the compiler is finding nil even though I assigned it a value in the locationManager function, so I'm guessing the two problems are connected. Thanks in advance
You can simulate location on the simulator using "Simulate location" button when running your app:
You can select one of the existing locations or you can create a GPX file (for example not a static single point but a route that will simulate constant changing of location). I would recommend you using https://mapstogpx.com/ to create GPX files.
Let me explain myself. I have created a Map where I show some locations (pins) and the user location. When I run the App, it opens and zooms in (span), then I want to move through the map, but the App "drags" the view back to the user location (it even zooms in back to normal state). My question is, how can I stop my App from doing that over and over again? because it is kind of annoying. Thanks in advance.
The function I used for this Span process was the following...
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span: MKCoordinateSpan = MKCoordinateSpanMake(1.0, 1.0)
let ubicacionUsuario: CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(ubicacionUsuario, span)
mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
}
Inside of your didUpdateLocations function, you can create a counter. Essentially, what the counter would do is update and refresh the user's location on the map for a specific number of iterations. After that, you can use the .stopUpdatingLocation method of the CLLocationManager. So, for your case, you would have something like below:
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
// Top level class stuff, create CLLocationManager Instance
var manager = CLLocationManager()
// set initial value of counter to 0
var updateCount = 0
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//If the location has updated less than 3 times, continue to update the location
if updateCount < 3 {
let region: MKCoordinateRegion = MKCoordinateRegionMake(ubicacionUsuario, span)
mapView.setRegion(region, animated: true)
updateCount += 1
} else {
// Once the update has occurred a satisfactory number of times, prevent the update from automaitcally occuring again
manager.stopUpdatingLocation()
}
}
}
Im creating this app, and it needs to get the users location - its all working properly, the thing is, that the time from accepting the use of location services, to getting the actual location takes like 5 seconds - is this normal?
I've used other apps, where it goes much faster..
Here's what my code looks like:
override func viewDidLoad() {
super.viewDidLoad()
// Ask for Location-Authorisation from the User.
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.requestLocation()
}
mapView.delegate = self
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue: CLLocationCoordinate2D = manager.location!.coordinate
let initialLocation = CLLocation(latitude: locValue.latitude, longitude: locValue.longitude)
self.centerMapOnLocation(initialLocation)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("could not get location")
}
But the time from the application gets the location to put into the centerMapOnLocation-function, seems just to be quite long. What is to be expected, when getting a users location? I'm testing on a wifi connection, so I know its not because the internet is slow, or its a bad connection...
Anyone have an idea? :)
Best regards!
Try setting the accuracy and use locationManager.startUpdatingLocation(). I do that, and get answer within a second (on the device).
From the documentation of requestLocation():
This method returns immediately. Calling it causes the location manager to obtain a location fix (which may take several seconds) and call the delegate’s locationManager(_:didUpdateLocations:) method with the result.
Source
So basically, everything is fine with your code, it's just how the framework is built.
When initializing your location manager, add startUpdatingLocation():
let manager = CLLocationManager()
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.requestLocation()
manager.startUpdatingLocation()
Without startUpdatingLocation() geo-location takes about 5 seconds, with it, the request executes nearly immediately.
If you don't want to delay the app's launch for the location manager, consider deploying two location managers (in the app delegate), tasking one with generating a location quickly and the other with generating a location accurately:
fastLoc.delegate = self
fastLoc.desiredAccuracy = kCLLocationAccuracyThreeKilometers
fastLoc.requestWhenInUseAuthorization()
fastLoc.startUpdatingLocation()
bestLoc.delegate = self
bestLoc.desiredAccuracy = kCLLocationAccuracyBest
bestLoc.requestWhenInUseAuthorization()
bestLoc.requestLocation()
The combination of 3 km accuracy with startUpdatingLocation() should return a location almost instantly, almost always before the root view controller is even ready to go. bestLoc manager is likely to return a location well after the user has launched the app but it will be very accurate.
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
switch manager {
case fastLoc:
fastLoc.stopUpdatingLocation()
deviceLocation = locations.last! // set property with fast loc
case bestLoc:
deviceLocation = locations.last! // overwrite property with best loc
default:
break
}
}
I am trying to get the user's location at the time of a button press, however I am having trouble setting up the location code. I've been looking between various answers on Stackoverflow but I can't get anything to work for me.
class MyViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedAlways || status == .AuthorizedWhenInUse {
let latitude = self.locationManager.location?.coordinate.latitude
let longitude = self.locationManager.location?.coordinate.longitude
print("coordinates:")
print(latitude)
print(longitude)
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locationValue : CLLocationCoordinate2D = manager.location!.coordinate
print("locations = \(locationValue.latitude) \(locationValue.longitude)")
}
However I just get nils from the prints in didChangeAuthorizationStatus and nothing ever prints from didUpdateLocations. Im also really confused about where to put startUpdatingLocation(). Some answers place it directly in viewDidLoad as I have here, others place it in didChangeAuthorizationStatus, and I saw another place it inside an if CLLocationManager.locationServicesEnabled() in didLoad. What is the correct way to do this? And also what have I done wrong that I'm not getting any values printing? I'm running on the emulator, have location turned on and allowed permissions in the pop-up, and have the emulator set to a lat/long custom location, and I have added the values in pList.
edit: even tried copy/pasting the code from this to get user's location only once but it returns (kCLErrorDomain error 0.). I added a 'requestWhenInUseAuthorization()` to their code but it still fails.
get nils from the prints in didChangeAuthorizationStatus
Because we don't have any locations yet. That's the wrong place to ask for that information. All that happened is that we are now authorized.
nothing ever prints from didUpdateLocations
Because you're running on the simulator, perhaps. Try running on a device.
And, if your goal is just to get the location and stop, don't use startUpdatingLocation; call requestLocation. That's what it's for.
What I want to do is have a button that the user can click that would save their current location. Then, on a map, a pin would appear where the save location is. How would I go about doing this? I've searched for some sample code but I can't find any that work or are in Swift.
I have it so the user can also see where they are at at all times. Bellow is what I currently have for code.
import UIKit
import CoreLocation
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
#IBOutlet var Map: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
locationManager.delegate = self
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!) {
println("Updating Location \(newLocation.coordinate.latitude) , \(newLocation.coordinate.longitude) ")
let span = MKCoordinateSpanMake(0.0009, 0.0009)
let region = MKCoordinateRegion(center: newLocation.coordinate, span: span)
Map.setRegion(region, animated: false)
}
}
What would I add to this code to accomplish my goal that I described in my first paragraph?
Try like this:
Create your button action to findUserLocationAndDropPin():
Capture the userLocationCoordinates using
CLLocationCoordinate2DMake();
Create your pinForUserLocation using MKPointAnnotation();
Assign your pinForUserLocation.coordinate to be equal to
userLocationCoordinates;
Get your mapView and addAnnotation;
Finally ask mapView to showAnnotations.
This code is what I mean and should do that, at least until iOS 8.4 :
#IBAction func findUserLocationAndDropPin(sender: UIButton) {
var userLocationCoordinates = CLLocationCoordinate2DMake(locationManager.location.coordinate.latitude, locationManager.location.coordinate.longitude)
var pinForUserLocation = MKPointAnnotation()
pinForUserLocation.coordinate = userLocationCoordinates
mapView.addAnnotation(pinForUserLocation)
mapView.showAnnotations([pinForUserLocation], animated: true)
}
Good question!
Try adding an array that stores newLocation.coordinate when an IBAction takes place. Then, you can set a pin by using this sample code as an example:
override func viewDidLoad() {
super.viewDidLoad()
// Set map view delegate with controller
self.mapView.delegate = self
let newYorkLocation = CLLocationCoordinate2DMake(40.730872, -74.003066)
// Drop a pin
let dropPin = MKPointAnnotation()
dropPin.coordinate = newYorkLocation
dropPin.title = "New York City"
mapView.addAnnotation(dropPin)
}
But then just set dropPin.coordinate to be the value stored in the array.
Ok, so firstly you want to get permission from the user:
Add the CoreLocation framework
Update info.plist by adding NSLocationWhenInUseUsageDescription
Your code in viewDidLoad is correct
You can use the simpler method:
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { }
Inside that, set:
var userLocation : CLLocation = locations[0] as! CLLocation
Now create a CLLocationCoordinate2D by using userLocation.latitude and .longitude
create an annotation with MKPointAnnotation(), and set annotation.coordinate to be the CLLocationCoordinate2D above.
set the .title if required
map.addAnnotation(annotation)
This will in effect add a pin every time the user's location is updated - so you might want to think about removing the previous pins. Also, it's not very effective if y you're getting updates every half second or so, so consider simply setting the mapView to show the region every time it is updated, rather than a pin.
Hope this helps!