MapKit Not Showing Location - ios

I've implemented MapKit into my Swift app and everything runs properly and when I run the app it shows a map. However, it's an overview of the United States and not where I want it to be.
I've imported the MapKit into ViewController and connected the MapView to the ViewController via an IBOutlet, however it's not working.
I didn't put the code in the viewDidLoad because the app crashed every time. Rather, I made a function and that seemed to do the trick. This is all of the code that I've got going for this map:
func mapMexico()
{
let lat:CLLocationDegrees = 20.648097
let long:CLLocationDegrees = -105.235168
let coordinate = CLLocationCoordinate2D(latitude: lat, longitude: long)
let latDelta:CLLocationDegrees = 0.01
let longDelta:CLLocationDegrees = 0.01
let span = MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: longDelta)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapView.setRegion(region, animated: true)
}

Related

Problem with location permission during first time launch only in simulator iPhone6 - XCode 9.4.1

I have one weird problem.
The problem occurs only in iPhone6 simulator.
When i started app first time, without permission, then show fail in this code. This code located in ViewDidLoad in main ViewController
manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.startUpdatingLocation()
var curLoc:CLLocation!
curLoc = manager.location
mapView.delegate = self
if (isLocationPermissionGranted() == false){
MapView.setRegion(MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 52.406464, longitude: 16.924997), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)), animated: true)
}else
{
MapView.setRegion(MKCoordinateRegionMake(CLLocationCoordinate2DMake(curLoc.coordinate.latitude, curLoc.coordinate.longitude), MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)), animated: true)
}
let getJSON = JSONDownload()
getJSON.JSONDownloader(MapView: MapView)
}
In else block I have error
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an
Optional value
But in any other simulator or my phone(iPhone 6s, iOS 11.4.1) only show
Could not inset legal attribution from corner 4
About this message I'm little confused too, because, I suppose, I have every permission option.
My permission stuff is:
in Info.plist
Privacy - Location When In Use Usage Description
Privacy - Location Usage Description
In code in ViewController
let manager = CLLocationManager()
In addition, I have protection against localized errors:
func isLocationPermissionGranted() -> Bool{
guard CLLocationManager.locationServicesEnabled() else{
return false
}
return [.authorizedAlways, .authorizedWhenInUse].contains(CLLocationManager.authorizationStatus())
}
Is any chance to fix it? :)
Thanks for answer! :)
In your code you are declaring curLoc as an implicitly unwrapped optional and then assigning manager.location to it; but manager.location is an optional and may be nil. There are a number of reasons that location could be nil; It takes time for a device to determine its location or the user may have denied location access.
Whatever the reason, when you subsequently access curLoc when it contains nil you get an exception because the contract of an implicitly unwrapped optional is that it won't be nil.
You need to unwrap manager.location safely in order to avoid a crash.
mapView.delegate = self
if let curLoc = manager.location, isLocationPermissionGranted() {
MapView.setRegion(MKCoordinateRegionMake(CLLocationCoordinate2DMake(curLoc.coordinate.latitude, curLoc.coordinate.longitude), MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)), animated: true)
} else {
MapView.setRegion(MKCoordinateRegion(center: CLLocationCoordinate2D(latitude: 52.406464, longitude: 16.924997), span: MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)), animated: true)
}

why CoreLocation unable to fetch new GPS data and Mapkit display this old GPS data

I am working on MapKit and core location to display my current GPS location.
The code is working ok but with some problems.
The problem is as follows:
I turn on my app in an open area like on the roadside. The app is able to get my current GPS location and display it on the Map.
I walk into a building with the app on. When inside, I launch the page to show the GPS location. It shows my previous GPS location. As I know, when I am inside the building, the Mapkit and Corelocation should not be able to get GPS. But in this case, it shows my previous GPS data!
I walk out of the building with the app on. In the open space I launch the page to show my current GPS location but the app is unable to get my new GPS location but displays the previous GPS data. In this case the app should fetch a new GPS location. I have to try a few times to launch the page (Navigate from GPS-VC to home-VC, from home click a button to launch the GPS-VC to get GPS).
Why is the GPS so slow even though I am in the open space with good signal strength?
Is there a difference to call these methods:
LocationManager.startUpdatingLocation()
LocationManager.requestLocation()
Here the code:
#IBOutlet weak var Map: MKMapView!
var locationMgr : CLLocationManager!
override func viewDidload(){
if(CLLocationManager.locationServicesEnabled() )
{
locationMgr = CLLocationManager()
locationMgr.delegate = self
locationMgr.desriedAccuracy = kCLLocationAccuracyBest
locationMgr.requestWhenInuseAuthorization()
locationMgr.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLoction: CLLocation = locations[0]
let latitude = userLoction.coordinate.latitude
let longitude = userLoction.coordinate.longitude
let latDelta: CLLocationDegrees = 0.05
let lonDelta: CLLocationDegrees = 0.05
let span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
let dropin = MKPointAnnotation()
dropin.coordinate = location
droping.title = "Here"
self.Map.setRegion(region, animated: true)
self.Map.addAnnotation(dropin)
self.Map.showsUserLocation = true
}
I'm not sure this will solve all 3 of your issues but I spotted the following issues in your delegate method:
the locations array is sorted in ascending time order so locations.last will contain the most recent location.
This method might be called with old cached values so you need to check the timestamp of the location to decide if it's worth using.

Zoom in on user location in iOS

I've been trying to solve this for a few hours and I can't seem to arrive at a solution. I am trying to create a button on my map view that zooms in on the users location when pressed. Here is the code for the function that pertains to the button:
func zoomInOnLocation() {
let userLocation = MKUserLocation()
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()
let currentLocation: CLLocation? = userLocation.location
let latitude = currentLocation?.coordinate.latitude
let longitude = currentLocation?.coordinate.longitude
let span: MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude!, longitude!)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: true)
}
When I click the button in the simulator, I receive an error stating fatal error:
unexpectedly found nil while unwrapping an Optional value
with the fifth line mapDelegate.mapView!... highlighted in red. Also, I added the proper tag to Info.plist. Any help is much appreciated.
Check this :
if #available(iOS 9.0, *) {
locationManager.requestLocation()
} else {
// Fallback
}
let latitude:CLLocationDegrees = //insert latitutde
let longitude:CLLocationDegrees = //insert longitude
let latDelta:CLLocationDegrees = 0.05
let lonDelta:CLLocationDegrees = 0.05
let span = MKCoordinateSpanMake(latDelta, lonDelta)
let location = CLLocationCoordinate2DMake(latitude, longitude)
let region = MKCoordinateRegionMake(location, span)
mapView.setRegion(region, animated: false)
For more : Making the map zoom to user location and annotation (swift 2)
So you probably do not want to to interact with the mapView delegate as you are doing right now.
How about adding the delegates to the class of the view that holds the mapView, like this:
class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
and setting the delegates in viewDidLoad():
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
mapView.delegate = self
}
And of course you want to have the locationManager and userLocation set up:
let locationManager = CLLocationManager()
var userLocation = CLLocation()
Notice that userLocation is a variable because most likely you would want to update it at some point.
This is how you probably want to work with locationManager:
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
You would make changes according to the needs of your app, and taking into account that the desired accuracy has an impact on battery life. Also, are you starting and stopping updates on userLocation? Because I do not see that in your code, unless you are doing it outside of this function.
A good practice is to try to minimize what an specific function does down to one task. You probably want to do all this setup elsewhere and then only zoom in inside the function. :)
Finally, in order to zoom in, you can change the values of MKCoordinateSpanMake, and remember that larger span values zoom in the map, so a smaller area is viewable.
let userLocationCoordinates = CLLocationCoordinate2D(latitude: userLocation.coordinate.latitude, longitude: userLocation.coordinate.longitude)
let span = MKCoordinateSpanMake(0.3, 0.3)
let region = MKCoordinateRegion(center: userLocationCoordinates, span: span)
mapView.setRegion(region, animated: true)
Hopefully that helps you out a bit, let me know how it goes!
Perhaps this will help. I created this function to zoom into an area defined by an array of positions, ranging from just the current user location out to the area around a set of points making up a polyline. The function provides for a buffer around the points based on a regionPaddingFactor constant set in my system constants.
func setRectView(_ locations: [MKAnnotation], mapView: MKMapView) // Size the area for display and reset the view
{
var maxLat = -90.0
var minLat = 90.0
var maxLon = -180.0
var minLon = 180.0
if locations.count >= 1 {
for waypoint in locations {
maxLat = max(maxLat, waypoint.coordinate.latitude)
minLat = min(minLat, waypoint.coordinate.latitude)
maxLon = max(maxLon, waypoint.coordinate.longitude)
minLon = min(minLon, waypoint.coordinate.longitude)
}
let loc = CLLocationCoordinate2DMake((maxLat-fabs(maxLat - minLat)/2), (maxLon-fabs(maxLon - minLon)/2))
let span = MKCoordinateSpanMake(0.001 + (1.0 + Setting.shared.regionPaddingFactor) * fabs(maxLat - minLat), 0.001 + (1.0 + Setting.shared.regionPaddingFactor) * fabs(maxLon-minLon))
// The 0.001 values above ensure that you do not get a 0.0 valued span if all of the points have the same latitude, longitude, or both, or if there is only one point
// The regionPaddingFactor is a constant to allow some space around the points passed in
let reg = MKCoordinateRegionMake(loc, span)
mapView.setRegion(reg, animated: true)
mapView.animatedZoom(zoomRegion: reg, duration: 0.8)
}
}
In the calling code, I provide for 3 settings that rotate as the user presses the button:
Show a tight view (just pass current location in the call)
Show the whole route (pass all points in the template)
Change to manual zooming / positioning
The last option is needed since I call the function whenever a new current position is received to reposition the view based on current location, which repeatedly refocuses the view if the user is trying to reposition the map.
If you don't want the flexibility of sending different position arrays, you can do the positioning here using mapView.annotations or just the current location as the array.

Swift 2 - Uber-like location picker with MKMapView

I'm trying to make an uber-like location picker from a small MKMapView in my class. My problem is the following :
Since I want to have the initial region to be centered at the user current location, I set the initial region inside the location manager function like this:
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let locValue:CLLocationCoordinate2D = (locations.last?.coordinate)!
let latDelta = 0.005
let lonDelta = 0.005
let span:MKCoordinateSpan = MKCoordinateSpan(latitudeDelta: latDelta, longitudeDelta: lonDelta)
let region:MKCoordinateRegion = MKCoordinateRegionMake(locValue, span)
self.locationMap.setRegion(region, animated: false)
}
The problem with this is that every time that the user tries to drag the map region to pick a location, obviously since the location is being always updated and the function is being called at everytime the location is updates, the map region goes back to its initial point as the function above states.
Another thing is that if I try to extract the locValue variable and assign it to a instance variable of the class within the function adding a line like this :
self.userLocation = locValue
self.userLocation won't change. If you have any suggestion on how to get a single location without updating it or how to fix either one of these problems it would be really appreciated if you could let me know.
Thanks.

Does apple maps and MapKit use the same API?

When I do a search in the Apple maps and one in my app using MapKit I get two different results for "New York".
Do they both use the same api?
If I do a search for "New York" in apple maps it will place the pointer in the center of NY city. But if I do a search for "New York" with MapKit using MKLocalSearchRequest and naturalLanguageQuery it will place the pointer a bit off, not even in Manhattan.
code:
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
localSearchRequest = MKLocalSearchRequest()
localSearchRequest.naturalLanguageQuery = "New York"
localSearch = MKLocalSearch(request: localSearchRequest)
localSearch.startWithCompletionHandler { (localSearchResponse, error) -> Void in
if localSearchResponse == nil || self.mapView == nil{
var alert = UIAlertView(title: "Not found", message: "Try again", delegate: self, cancelButtonTitle: "OK")
alert.show()
return
} else {
let location = CLLocationCoordinate2D(latitude: localSearchResponse.boundingRegion.center.latitude, longitude: localSearchResponse.boundingRegion.center.longitude)
let span = MKCoordinateSpanMake(0.05, 0.05)
let region = MKCoordinateRegion(center: location, span: span)
self.mapView.setRegion(region, animated: false)
self.pointAnnotation = MKPointAnnotation()
self.pointAnnotation.coordinate = location
self.mapView.addAnnotation(self.pointAnnotation)
}
}
}
they don't use the same api for displaying so I'd also assume they don't use the public API for searching.
Especially given the fact that the app came earlier than the API
BUT thats likely besides the point
You don't set the region property: "A map region that provides a hint as to where to search." (at least it isn't the same as in apple maps it seems)
for me it returns only ONE result as well [using mapkit]

Resources