How to go to user location with Mapkit (Swift) - swift

I am new to app development and I have been trying to create an app which will use core location manager to find the users location and then display it with mapkit. Below is the code I came up with. I haven't been able to fix it, does anyone know what I'm doing wrong? Thanks.
//
// ViewController.swift
// MapKit Test
//
// Created by TMT on 7/11/15.
// Copyright (c) 2015 TMT Inc. All rights reserved.
//
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.showsUserLocation = true
mapView.showsPointsOfInterest = true
mapView.delegate = self
let locationManager = CLLocationManager()
// Ask for Authorisation from the User.
locationManager.requestAlwaysAuthorization()
// For use in foreground
locationManager.requestWhenInUseAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
#NSCopying var location: CLLocation! { get }
var span = MKCoordinateSpanMake(0.2
, 0.2)
var region = MKCoordinateRegion(center: location, span: span)
mapView.setRegion(region, animated: true)
var request = MKLocalSearchRequest()
request.naturalLanguageQuery = "library"
// 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 are not handling the delegate method for the location/map. Your code is setting up the map and location frameworks and delegate methods. You have initialized them and told the compiler you want to do something with mapkit/corelocation. So now you need to to handle the delegate methods MKMapViewDelegate, CLLocationManagerDelegate which you have included, and set to self
Place the delegate handling in addition to your code somewhere
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
//Get map location
let location = locations.last as! CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
self.mapView.setRegion(region, animated: true)
//Get co ordinates
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: {(placemarks, error)->Void in
if (error != nil) {
println("Error: " + error.localizedDescription)
return
}
if placemarks.count > 0 {
let pm = placemarks[0] as! CLPlacemark
self.displayLocationInfo(pm)
} else {
println("Error with the data.")
}
})
}
func displayLocationInfo(placemark: CLPlacemark) {
//Remove observer
self.locationManager.stopUpdatingLocation()
println(placemark.locality)
println(placemark.postalCode)
println(placemark.administrativeArea)
println(placemark.country)
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("Error: " + error.localizedDescription)
}

Related

Xcode Swift, Geo Location won't show where i am

any one understand why Geo location won't show me where i am, also the permissions don't work over..... I'm baffled... laptop location is fine, also the app permissions are also set, also the Allow permissions tap, box for the user won't appear either
(iv explained this all above and it won't post unless i type more stuff in the box, but could some one explain why this code doesn't work norrr does it display no errors at all, i had also checked - DEBUG - locations... still nothing
import UIKit
import MapKit
import CoreLocation
class MapScreen: UIViewController {
#IBOutlet weak var mapView: MKMapView!
let locationManager = CLLocationManager()
let regionInMeters: Double = 10000
override func viewDidLoad() {
super.viewDidLoad()
checkLocationServices()
}
func setupLocationManager() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
}
func centerViewOnUserLocation() {
if let location = locationManager.location?.coordinate {
let region = MKCoordinateRegion.init(center: location, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
}
func checkLocationServices() {
if CLLocationManager.locationServicesEnabled() {
setupLocationManager()
checkLocationAuthorization()
} else {
// Show alert letting the user know they have to turn this on.
}
}
func checkLocationAuthorization() {
switch CLLocationManager.authorizationStatus() {
case .authorizedWhenInUse:
mapView.showsUserLocation = true
centerViewOnUserLocation()
locationManager.startUpdatingLocation()
break
case .denied:
// Show alert instructing them how to turn on permissions
break
case .notDetermined:
locationManager.requestWhenInUseAuthorization()
case .restricted:
// Show an alert letting them know what's up
break
case .authorizedAlways:
break
}
}
}
extension MapScreen: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let location = locations.last else { return }
let region = MKCoordinateRegion.init(center: location.coordinate, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
checkLocationAuthorization()
}
}
Did you add the permission strings to your info.plist?
You need to add explanations for these otherwise the permission prompt won't appear, and no location updates will be send to your app.
NSLocationAlwaysUsageDescription and NSLocationWhenInUseUsageDescription
You should also get an error for this in your console so check that as well.

Present user location swift

I'm new to Swift, I want to show user location on map, I added MKMapView, and added an outlet, here is my code:
import UIKit
import Foundation
import MapKit
import CoreLocation
class ViewController: 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)
self.map.showsUserLocation = true
}
override func viewDidLoad() {
super.viewDidLoad()
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
But when I run the app on the simulator it shows me some other location on the USA. But I'm from another place that is not even close to the USA.
Your code is fine, that's because you run it on simulator, select Debug-->Simulate Location-->Choose some other location and you will see that location on the screen
Because simulator use fake location for testing purpose. you can also change that location See in the image(https://i.stack.imgur.com/2GN7x.png).
If you run on actual device it shows your current location.

Googlemaps not allowing me to locate the users location?

I am trying to create a view controller on swift that shows where the user is located. I have already implemented google maps, so now all I have to do is plug in the correct code. When doing so, I keep getting these two error messages then the app crashes. Can someone help me with figuring out a solution> any and all help is appreciated.
import UIKit
import Foundation
import Firebase
import MapKit
import GoogleMaps
import CoreLocation
class mainViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
let defaults = UserDefaults.standard
let locationManager = CLLocationManager()
var mapView = GMSMapView()
var camera = GMSCameraPosition()
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
GMSServices.provideAPIKey("AIzaSyBDOLisA3c-wDTbkbSssAxEb3iLw7Y5vHo")
let camera = GMSCameraPosition.camera(withLatitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!, zoom: 17)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
view = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!)
marker.snippet = "Current Location"
marker.map = mapView
self.mapView.addSubview(mapView)
view.backgroundColor = GREEN_Theme
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Welcome"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(Logout))
}
#objc func Logout() {
print("Logged Out")
do {
// I am receiving this error message on the auth.auth().signOut() "Use of unresolved identifier 'Auth'"
try Auth.auth().signOut()
defaults.set(false, forKey: "user is logged in")
let loginController = UINavigationController(rootViewController: LoginController())
present(loginController, animated: true, completion: nil)
} catch let err {
print(err.localizedDescription)
}
}
}
Your issue is that the CLLocationManager does not have enough time to fetch the info and in the meantime other functions ask for that info which its still nil.
The below will take care the issue, it also stops updating the locations all the time which can be battery draining especially considering that you have set AccuracyBest.
func getLocation(){
locationManager=CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]){
let lastLocation=locations[locations.count-1]
if lastLocation.horizontalAccuracy>0{
locationManager.stopUpdatingLocation()
let latitude = lastLocation.coordinate.latitude
let longitude = lastLocation.coordinate.longitude
GMSServices.provideAPIKey("AIzaSyBDOLisA3c-wDTbkbSssAxEb3iLw7Y5vHo")
// everything that is going to require the latitude and longitude from the location manager goes here
let camera = GMSCameraPosition.camera(withLatitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!, zoom: 17)
let mapView = GMSMapView.map(withFrame: CGRect.zero, camera: camera)
self.view = mapView
let marker = GMSMarker()
marker.position = CLLocationCoordinate2D(latitude: (self.locationManager.location?.coordinate.latitude)!, longitude: (self.locationManager.location?.coordinate.latitude)!)
marker.snippet = "Current Location"
marker.map = mapView
self.mapView.addSubview(mapView)
}
}
Your viewDidLoad should have:
override func viewDidLoad() {
super.viewDidLoad()
getLocation()
view.backgroundColor = GREEN_Theme
navigationController?.navigationBar.prefersLargeTitles = true
navigationItem.title = "Welcome"
navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Logout", style: .plain, target: self, action: #selector(Logout))
}
You are using Google Map as your map view, which means that you create an instance of the GMSMapView class. That's an object. You have one. And I assume that it's IBOutlet-wired. It comes with several delegate methods. So you may want to set its delegate. And you want your view controller to receive data from GMSMapView. So you set the delegate of that class to self (your view controller).
import UIKit
import Foundation
import Firebase
import GoogleMaps
import CoreLocation
class mainViewController: UIViewController, CLLocationManagerDelegate, GMSMapViewDelegate {
// MARK: - Instance variables
private let locationManager = CLLocationManager()
// MARK: - IBOutlets
#IBOutlet weak var mapView: GMSMapView!
// MARK: - IBActions
// MARK: - Life cycle
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
mapView.isMyLocationEnabled = true
}
// MARK: - Life cycle
// MARK: - GMSMapView delegate methods
func mapView(_ mapView: GMSMapView, idleAt position: GMSCameraPosition) {
reverseGeocodeCoordinate(position.target) // sending data when the mapView is not moved or pinched by the finger //
}
func reverseGeocodeCoordinate(_ coordinate: CLLocationCoordinate2D) {
let geocoder = GMSGeocoder()
geocoder.reverseGeocodeCoordinate(coordinate) { response, error in
guard let address = response?.firstResult(), let lines = address.lines else {
return
}
...
...
}
}
}

Swift MapView Stuck Around User's Current Location

Currently, my code drops a pin on the user's current location. There is one small problem when I try to move the map around, because the view will shift back and be centered around that current location pin. I want the user be able to navigate the map and move it around, and if the user switches view controllers (goes to another tab) and comes back, the map will be centered around the user location pin. I have been trying to modify this code to do this, but I have not had any luck where to start.
import UIKit
import MapKit
import CoreLocation
let newPin = MKPointAnnotation()
class MapVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// User's location
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if #available(iOS 8.0, *) {
locationManager.requestAlwaysAuthorization()
} else {
// Fallback on earlier versions
}
locationManager.startUpdatingLocation()
// add gesture recognizer
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(MapVC.mapLongPress(_:))) // colon needs to pass through info
longPress.minimumPressDuration = 1.5 // in seconds
//add gesture recognition
map.addGestureRecognizer(longPress)
}
// func called when gesture recognizer detects a long press
func mapLongPress(_ recognizer: UIGestureRecognizer) {
print("A long press has been detected.")
let touchedAt = recognizer.location(in: self.map) // adds the location on the view it was pressed
let touchedAtCoordinate : CLLocationCoordinate2D = map.convert(touchedAt, toCoordinateFrom: self.map) // will get coordinates
let newPin = MKPointAnnotation()
newPin.coordinate = touchedAtCoordinate
map.addAnnotation(newPin)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
map.removeAnnotation(newPin)
let location = locations.last! as CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
//set region on the map
map.setRegion(region, animated: true)
newPin.coordinate = location.coordinate
map.addAnnotation(newPin)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Your code has several problems:
You declare a variable newPin at global scope and in mapLongPress(...) you declare a new variable let newPin = ... locally so the global newPin isn't used.
In didUpdateLocations() you first remove the (global) newPin annotation (why??) and set it again at the end of the function. Because the global newPin was never set to anything useful this will never get the desired result.
Furthermore, in didUpdateLocations() you set the map's region and center point to the current location. This is done on every location update, giving weird results when trying to pan the map.
To set center and region when the view appears, try something like that:
class MapVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
let locationManager = CLLocationManager()
// class variable for the current location
var lastLocation: CLLocation?
override func viewDidLoad() {
// ...
}
override func viewDidAppear(_ animated: Bool) {
if self.lastLocation != nil {
// set center and region to current location
let center = CLLocationCoordinate2D(latitude: self.lastLocation.coordinate.latitude, longitude: self.lastLocation.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
//set region on the map
map.setRegion(region, animated: true)
}
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
self.lastLocation = locations.last
}
}

Swift MkMapView Map is always centered around current location

Currently, my code drops a pin on the user's current location. There is one small problem when I try to move the map around, because the view will shift back and be centered around that current location pin. I want the user be able to navigate the map and move it around, and if the user switches view controllers (goes to another tab) and comes back, the map will be centered around the user location pin. I have been trying to modify this code to do this, but I have not had any luck where to start.
import UIKit
import MapKit
import CoreLocation
let newPin = MKPointAnnotation()
class MapVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {
#IBOutlet weak var map: MKMapView!
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
// User's location
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
if #available(iOS 8.0, *) {
locationManager.requestAlwaysAuthorization()
} else {
// Fallback on earlier versions
}
locationManager.startUpdatingLocation()
// add gesture recognizer
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(MapVC.mapLongPress(_:))) // colon needs to pass through info
longPress.minimumPressDuration = 1.5 // in seconds
//add gesture recognition
map.addGestureRecognizer(longPress)
}
// func called when gesture recognizer detects a long press
func mapLongPress(_ recognizer: UIGestureRecognizer) {
print("A long press has been detected.")
let touchedAt = recognizer.location(in: self.map) // adds the location on the view it was pressed
let touchedAtCoordinate : CLLocationCoordinate2D = map.convert(touchedAt, toCoordinateFrom: self.map) // will get coordinates
let newPin = MKPointAnnotation()
newPin.coordinate = touchedAtCoordinate
map.addAnnotation(newPin)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
map.removeAnnotation(newPin)
let location = locations.last! as CLLocation
let center = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
//set region on the map
map.setRegion(region, animated: true)
newPin.coordinate = location.coordinate
map.addAnnotation(newPin)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
You can use custom location manager class and call the singleton function in didfinishlaunching with option and save latitude and longitude in UserDefault .Set camera position in viewDidLoad for mapView class
1.Make singleton class
var locationShareInstance:locationManagerClass = locationManagerClass()
class locationManagerClass: NSObject, CLLocationManagerDelegate, WebServiceDelegate , UIAlertViewDelegate
{
var locationManager = CLLocationManager()
class func sharedLocationManager() -> locationManagerClass
{
locationShareInstance = locationManagerClass()
return locationShareInstance
}
func startStandardUpdates() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.activityType = .automotiveNavigation
locationManager.distanceFilter = 10
locationManager.pausesLocationUpdatesAutomatically = false
if (Bundle.main.object(forInfoDictionaryKey: "NSLocationWhenInUseUsageDescription") != nil) {
locationManager.requestWhenInUseAuthorization()
}
locationManager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
// If it's a relatively recent event, turn off updates to save power.
let location: CLLocation = locations.last!
let strLocation = "\(location.coordinate.latitude)"
if strLocation == "" {
}else{
UserDefaults.standard.set("\(location.coordinate.latitude)", forKey: "lat")
UserDefaults.standard.set("\(location.coordinate.longitude)", forKey: "long")
UserDefaults.standard.synchronize()
debugPrint("Spedd: \(location.speed)")
// self.updateLocationToServer()
self.stopStandardUpdate()
}
}
func stopStandardUpdate(){
locationManager.stopUpdatingLocation()
}
//MARK:- WHEN DENIED
func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
if status == CLAuthorizationStatus.denied {
NSLog("DENIAL")
UserDefaults.standard.set("\(0.0)", forKey: "lat")
UserDefaults.standard.set("\(0.0)", forKey: "long")
self.generateAlertToNotifyUser()
}
}
func generateAlertToNotifyUser() {
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.notDetermined{
var title: String
title = ""
let message: String = "Location Services are not able to determine your location"
let alertView: UIAlertView = UIAlertView(title: title, message: message, delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "Settings")
alertView.show()
}
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.denied{
var title: String
title = "Location services are off"
let message: String = "To post spots or find near by spots, you must turn on Location Services from Settings"
let alertView: UIAlertView = UIAlertView(title: title, message: message, delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "Settings")
alertView.show()
}
if CLLocationManager.authorizationStatus() == CLAuthorizationStatus.notDetermined
{
startStandardUpdates()
}
}
}
Call this functions in didfinishlaunchingwithoption
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let locationManager = locationManagerClass.sharedLocationManager()
locationManager.startStandardUpdates()
}
3.Set camera in viewDidLoad of your class
if UserDefaults.standard.object(forKey: "lat") != nil {
let lat = UserDefaults.standard.object(forKey: "lat") as! String
let long = UserDefaults.standard.object(forKey: "long") as! String
var userLoc = CLLocationCoordinate2D()
userLoc.latitude = CDouble(lat)!
userLoc.longitude = CDouble(long)!
let span = MKCoordinateSpanMake(0.02, 0.02)
let region = MKCoordinateRegion(center: userLoc, span: span)
mapVw.setRegion(region, animated: true)
mapVw.showsUserLocation = true
}