swift 3 error using MapKit - ios

I'm making a map
Add the two variables in info.plist "Privacy - Location When Usage Description", "Privacy - Location Always Usage Description"
Error:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid Region '
My code:
import UIKit
import MapKit
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
var manager: CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
manager = CLLocationManager()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
let uilpgr = UILongPressGestureRecognizer(target: self, action:Selector(("action:")))
uilpgr.minimumPressDuration = 2.0
map.addGestureRecognizer(uilpgr)
}
func action(gestureRecognizer:UIGestureRecognizer){
if gestureRecognizer.state == UIGestureRecognizerState.began{
let touchPoint = gestureRecognizer.location(in: self.map)
let newCoordinate = self.map.convert(touchPoint, toCoordinateFrom: self.map)
let annotation = MKPointAnnotation()
annotation.coordinate = newCoordinate
annotation.title = "Meu lugar"
self.map.addAnnotation(annotation)
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0]
let latitude = userLocation.coordinate.latitude
let longitude = userLocation.coordinate.longitude
let coordinate = CLLocationCoordinate2DMake(longitude,latitude)
let latDelta: CLLocationDegrees = 0.01
let lonDelta: CLLocationDegrees = 0.01
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let region:MKCoordinateRegion = MKCoordinateRegionMake(coordinate, span)
self.map.setRegion(region, animated: false)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}

I think you forgot to import the CoreLocation framework. I don't think you are getting a valid location object back from the delegate method. Please, import the CoreLocation framework and test it again.

Your code in the locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) is redundant as you can just call self.map.setUserTrackingMode(.follow, animated: true)
If the user were to pan the map, user tracking will become disabled, so you would need to use this delegate mapView(_ mapView: MKMapView, didChange mode: MKUserTrackingMode, animated: Bool) to update the user tracking mode.

Related

Cannot convert value of type 'CLLocationCoordinate2D' to expected argument type 'CLLocationDegrees' (aka 'Double')

I have getting user's current location but getting this error at this line
let region : MKCoordinateRegion = MKCoordinateSpanMake(myLocation, span)
I am getting error at myLocation in above line
Cannot convert value of type 'CLLocationCoordinate2D' to expected argument type 'CLLocationDegrees' (aka 'Double')
I think there may be type casting problem or similar.
What should I do to handle this error I researched a lot of examples but none helped me.
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, CLLocationManagerDelegate {
let manager = CLLocationManager()
#IBOutlet weak var myMap: MKMapView!
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span : MKCoordinateSpan = MKCoordinateSpanMake(1, 1)
let myLocation : CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region : MKCoordinateRegion = MKCoordinateSpanMake(myLocation, span)
myMap.setRegion(region, animated: true)
self.myMap.showsUserLocation = true
}
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You want MKCoordinateRegionMake, not MKCoordinateSpanMake.
And there's lots of other fixes you should make:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span = MKCoordinateSpanMake(0.01, 0.01)
let myLocation = location.coordinate
let region = MKCoordinateRegionMake(myLocation, span)
myMap.setRegion(region, animated: true)
self.myMap.showsUserLocation = true
}

Downcast from 'CLLocation?' to 'CLLocation' only unwraps optionals; did you mean to use '!'?

I'm trying to display the users current location on a map view but I'm getting an error on the first line of the location manager function
Here is my code
import UIKit
import MapKit
class FirstViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapkitView: MKMapView!
var locationManager: CLLocationManager!
override func viewDidLoad()
{
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled())
{
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{
let location = locations.last as! CLLocation
let center = CLLocationCoordinate2DMake(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapkitView.setRegion(region, animated: true)
}
}
The error I'm getting is "Downcast from 'CLLocation?' to 'CLLocation' only unwraps optionals; did you mean to use '!'?
on line let location = locations.last as! CLLocation
You are force-casting an Optional CLLocationto CLLocation, that is why Swift suggests to simply force unwrap it:
let location = locations.last!
This version (and yours) will crash if locations is empty.
Thus I recommend to never force unwrap anything and use guardinstead:
guard let location = locations.last else {
return
}

User location won't come up in simulator in Xcode

I'm new to app development and I'm trying to get the user location to come up in the simulator but I keep getting the Use of unresolved identifier error. I have looked at other questions, which are very specific to their own projects, and have tried to approach my own app in a similar way but to not avail. Any help, por favor? Here's my code, and a link to a screenshot of Xcode.
import UIKit
import MapKit
import CoreLocation
class SecondViewController: UIViewController, CLLocationManagerDelegate {
//Map
#IBOutlet weak var map: MKMapView!
let manager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{ let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
self.map.showsUserLocation = true
}
override func viewDidLoad()
{
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
//This is where I get an error
map.setRegion(region, animated: true)**
}
Error: Use of unresolved identifier
Your let region:MKCoordinateRegion is a local identifier inside your delegate method:
func locationManager(_:didUpdateLocations) {...}
This is why you are getting Use of unresolved identifier. Make this identifier accessible throughout the class, the error will be gone. Like:
class SecondViewController: UIViewController, CLLocationManagerDelegate {
//Map
#IBOutlet weak var map: MKMapView!
var region = MKCoordinateRegion()
.......
.......
}
N.B: But this won't let you see anything in the map. Best way to see any output from your MapView is to put map.setRegion(region, animated: true) inside your delegate method:
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.first
let span = MKCoordinateSpanMake(0.01, 0.01)
let myLocation = CLLocationCoordinate2DMake((location?.coordinate.latitude)!, (location?.coordinate.longitude)!)
region = MKCoordinateRegionMake(myLocation, span)
map.setRegion(region, animated: true)
}
Use MKCoordinateRegion instance before viewdidload method
You can follow below code for reference.
class Test: UIViewController {
var region = MKCoordinateRegion()
override func viewDidLoad() {
super.viewDidLoad()
region = MKCoordinateRegionMake(myLocation, span)
}
}
You are getting Error because
the variable region inside viewDidLoad() method do not have access of region variable inside
viewDidLoad() method
//This is where I get an error
map.setRegion(region, animated: true)**
Solution :
Make region variable global to class so that that can be accessed from anywhere you want to.
Instead of this line inside func locationManager
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation,span)
Use
self.region = MKCoordinateRegionMake(myLocation,span)
Here is complete code That you can use.
import UIKit
import MapKit
import CoreLocation
class SecondViewController: UIViewController, CLLocationManagerDelegate {
//Map
#IBOutlet weak var map: MKMapView!
//global variable
var region:MKCoordinateRegion = MKCoordinateRegion()
let manager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation])
{ let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
self.region = MKCoordinateRegionMake(myLocation, span)
self.map.showsUserLocation = true
}
override func viewDidLoad()
{
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
//This is where I get an error
map.setRegion(region, animated: true)**
}
//
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
And more important if you are using simulator then you have to enable location simulation.

Find location name swift maps

I am creating a map using swift. How can i find the name of my current location as saved on Apple maps, like lets say I am at Walmart, how do i get it to print out the name of the location, and if the location it just prints out an address.
My current code is
class MapVC: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
let manager = CLLocationManager()
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let mylocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(mylocation, span)
map.setRegion(region, animated: true)
print(location.coordinate)
print(location.coordinate.latitude)
print(location.speed)
self.map.showsUserLocation = true
self.map.showsPointsOfInterest = true
}
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestAlwaysAuthorization()
manager.startUpdatingLocation()
}
You can use iOS native API to convert longitude and latitude to place name:
func reverseGeocodeLocation(_ location: CLLocation,
completionHandler: #escaping CLGeocodeCompletionHandler)
For example:
var geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(location, completionHandler: {(placemarks, error)->Void in
})
Get the place name by getting the first object of placemarks which is of type CLPlacemark. Then the CLPlacemark's name property is what you are after.

Why does this function keep looping?

func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
MapOutlet.setRegion(coordinateRegion, animated: true)
}
This function above within my view controller below continues to run although I never coded any loop in, can someone help spot the incorrect logic. Here is the rest of the view controller
import UIKit
import MapKit
import CoreLocation
class ViewControllerPublic: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
let initialLocation = CLLocation(latitude: 3.632488, longitude: -117.898886)
override func viewDidLoad() {
super.viewDidLoad()
centerMapOnLocation(initialLocation)
// Ask for Authorisation from the User.
self.locationManager.requestAlwaysAuthorization()
// For use in foreground
self.locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = manager.location!.coordinate
print("locations = \(locValue.latitude) \(locValue.longitude)")
let currentLocation = CLLocation(latitude: locValue.latitude, longitude: locValue.longitude)
centerMapOnLocation(currentLocation)
}
let regionRadius: CLLocationDistance = 2300
func centerMapOnLocation(location: CLLocation) {
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate,
regionRadius * 2.0, regionRadius * 2.0)
MapOutlet.setRegion(coordinateRegion, animated: true)
}
#IBOutlet weak var MapOutlet: MKMapView!
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You never invalidate the CLLocation manager so as #Ashish Kakkad said, whenever you get even the slightest location change your function is getting called again. If you don't want this behavior, then after you get a location in didUpdateLocations you need to do locationManager.stopUpdatingLocation(). Or, if you do want your app to update the map every time the location changes, you may want to think about changing your desired location accuracy.

Resources