Getting user's location not working after Swift 4 update - swift

I've just updated to the Xcode 9 and Swift 4 and it has broken at lot of my functions. One of which being how I get the user's location, zoom in on it on launch, detecting annotation selection and various other tasks. They don't work at all. My view controller class code is below.
import UIKit
import MapKit
import Firebase
import FirebaseDatabase
import Pulley
import CoreLocation
class ChildMapViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
let manager = CLLocationManager()
var isInitialized = false
func startBackgroundLocationUpdates() {
self.manager.delegate = self
manager.requestWhenInUseAuthorization()
manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers
manager.pausesLocationUpdatesAutomatically = true
manager.activityType = .fitness
manager.allowsBackgroundLocationUpdates = true
manager.startMonitoringSignificantLocationChanges()
manager.startUpdatingLocation()
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations[0]
if !isInitialized {
isInitialized = true
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.01, 0.01)
let myLocation:CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation, span)
mapView.setRegion(region, animated: true)
self.mapView.showsUserLocation = true
}
}
struct loc {
let title: String
let latitude: Double
let longitude: Double
}
var locs = [
loc(title: "New York, NY", latitude: 40.713054, longitude: -74.007228),
]
func placeAnnotations() {
let annotations = locs.map { location -> MKAnnotation in
let annotation = MKPointAnnotation()
annotation.coordinate = CLLocationCoordinate2D(latitude: location.latitude, longitude: location.longitude)
annotation.title = location.title
return annotation
}
mapView.addAnnotations(annotations)
}
var position:PulleyPosition!
func mapView(_ didSelectmapView: MKMapView, didSelect view: MKAnnotationView) {
Shared.shared.annotation = view.annotation!
if Shared.shared.annotation is MKUserLocation {
Shared.shared.nameString = "My Location"
} else {
loadData()
}
}
func mapView(_ mapView: MKMapView, didDeselect view:
MKAnnotationView) {
let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DrawerViewController")
if let drawer = self.parent?.parent as? PulleyViewController {
drawer.setDrawerContentViewController(controller: drawerContent, animated: false)
drawer.setDrawerPosition(position: PulleyPosition.partiallyRevealed, animated: true)
}
}
func loadData() {
let number = (Shared.shared.annotation?.title)!
if let number = number {
let ref = FIRDatabase.database().reference()
ref.child("safehouses").child("\(number)").observeSingleEvent(of: .value, with: { snapshot in
let snapDict = snapshot.value as? NSDictionary
let name = snapDict?["name"] as? String
let phone = snapDict?["phone"] as? String
let current = CLLocation(latitude: (self.manager.location?.coordinate.latitude)!, longitude: (self.manager.location?.coordinate.longitude)!)
let destination = CLLocation(latitude: Shared.shared.annotation.coordinate.latitude, longitude: Shared.shared.annotation.coordinate.longitude)
let distance2 = current.distance(from: destination)
let distance1 = round(distance2)
if distance1 >= 1000 {
if distance1 < 10000 {
let distance3 = distance1/1000
let distance = Double(round(10*distance3)/10)
Shared.shared.typeString = "Safehouse · " + String(distance) + " km"
} else {
let distance3 = distance1/1000
let distance = round(distance3)
Shared.shared.typeString = "Safehouse · " + String(distance) + " km"
}
} else {
let distance = self.forTailingZero(temp: distance1)
Shared.shared.typeString = "Safehouse · " + distance + " m"
}
if let name = name {
if let phone = phone {
Shared.shared.nameString = name
Shared.shared.phoneString = phone
let drawerContent = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "NewDrawerViewController")
if let drawer = self.parent?.parent as? PulleyViewController {
drawer.setDrawerContentViewController(controller: drawerContent, animated: false)
drawer.setDrawerPosition(position: PulleyPosition.partiallyRevealed, animated: true)
}
}
}
})
}
}
func forTailingZero(temp: Double) -> String{
var tempVar = String(format: "%g", temp)
return tempVar
}
func loop() {
let ref = FIRDatabase.database().reference()
ref.child("safehouses").observeSingleEvent(of: .value, with: { snapshot in
let snapDict = snapshot.value as? NSDictionary
let ii = snapDict?["number"] as? Int
let iii = Int(ii!)
var i = 1
while i <= iii{
let name = String(i)
ref.child("safehouses").child("\(i)").observeSingleEvent(of: .value, with: { snapshot in
let snapDict = snapshot.value as? NSDictionary
let longitude = snapDict?["longitude"]
as? String
let latitude = snapDict?["latitude"] as? String
if let longitude = longitude {
if let latitude = latitude {
let latitude1 = Double(latitude)
if let latitude1 = latitude1 {
let longitude1 = Double(longitude)
if let longitude1 = longitude1 {
self.locs.append(loc(title: name, latitude: latitude1, longitude: longitude1))
self.placeAnnotations()
}
}
}
}
})
i = i + 1
}
})
}
#IBOutlet weak var menuButton: UIBarButtonItem!
override func viewDidLoad() {
super.viewDidLoad()
self.revealViewController().rearViewRevealWidth = 175
self.revealViewController().toggleAnimationType = SWRevealToggleAnimationType.easeOut
if self.revealViewController() != nil {
menuButton.target = self.revealViewController()
menuButton.action = #selector(SWRevealViewController.revealToggle(_:))
self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
}
loop()
mapView.delegate = self
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestAlwaysAuthorization()
Shared.shared.mapView = self.mapView
startBackgroundLocationUpdates()
}
}
final class Shared {
static let shared = Shared()
var nameString : String!
var phoneString : String!
var annotation : MKAnnotation!
var mapView : MKMapView!
var typeString : String!
}

First add these property in info.plist
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>description1</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>description2</string>
<key>NSLocationUsageDescription</key>
<string>description3</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>accept to get location</string>
<key>UIBackgroundModes</key>
And then after copy this view controller in your project
import UIKit
import CoreLocation
class ViewController: UIViewController,CLLocationManagerDelegate {
var locationManager:CLLocationManager!
override func viewDidLoad() {
super.viewDidLoad()
determineMyCurrentLocation()
// Do any additional setup after loading the view.
}
func determineMyCurrentLocation() {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager!.allowsBackgroundLocationUpdates = true
locationManager!.pausesLocationUpdatesAutomatically = false
let value = locationManager.startMonitoringSignificantLocationChanges()
if CLLocationManager.locationServicesEnabled() {
locationManager.startUpdatingLocation()
}
}
func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
print("ankur :- \(region)")
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation:CLLocation = locations[0] as CLLocation
print("user latitude = \(userLocation.coordinate.latitude)")
print("user longitude = \(userLocation.coordinate.longitude)")
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error)
{
print("Error \(error)")
}
}
Last step :- Open Capabilities -> In background modes -> click on location updates
If any query comment it

You need to add these keys in info plist :
<key>UIBackgroundModes</key>
<array>
<string>location</string>
</array>

Related

How to replace new location coordinates in current location coordinates in MKMapView in swift

I am using map in Two viewcontrollers
Initially in first viewcontroller i am getting current location in map..
in second viewcontroller i am getting new location coordinates, which i am sending to firstview controller using delegate.. but here how to replace the delegate method coordinates with current location coordinates in first view controller
first view controller code: here in delegate method i am successfully having new location coordinates which i need replace with current location
in userDidEnterInformationdelegate method i am getting all values from 2nd view controller
import UIKit
import CoreLocation
import MapKit
class ProfileAddressViewController: UIViewController, CLLocationManagerDelegate, UISearchBarDelegate, DataEnteredDelegate {
var coordinate: CLLocationCoordinate2D = CLLocationCoordinate2D()
let locationManager = CLLocationManager()
var latitude: Double?
var logitude: Double?
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.requestAlwaysAuthorization()
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
}
}
func userDidEnterInformation(info: DataEnteredModelSave) {
print("map address viewcontroller data \(info)")
self.pincodeField.text = info.pinCode
self.cityField.text = info.cityField
self.latitude = info.zLatitude
self.self.logitude = info.zLongitude
print("new map address viewcontroller data info lat long \(self.latitude) \(self.logitude)")
}
#IBAction func submitButtonClicked(_ sender: UIButton) {
self.view.endEditing(true)
let viewController = self.storyboard?.instantiateViewController(withIdentifier: "NewZoomAddressViewController") as! NewZoomAddressViewController;
self.navigationController?.pushViewController(viewController, animated: true);
}
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
print(error)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
guard let _: CLLocationCoordinate2D = manager.location?.coordinate else { return }
let userLocation :CLLocation = locations.last! as CLLocation
latitude = userLocation.coordinate.latitude
logitude = userLocation.coordinate.longitude
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(userLocation) { (placemarks, error) in
if (error != nil){
print("error in reverseGeocode")
}
let placemark = placemarks! as [CLPlacemark]
if placemark.count>0{
let placemark = placemarks![0]
let placemarkDictonary: NSDictionary=placemark.addressDictionary as! NSDictionary
self.pincodeField.text=placemarkDictonary["ZIP"] as? String
self.cityField.text=placemarkDictonary["City"] as? String
}
}
let center = CLLocationCoordinate2D(latitude: latitude!, longitude: logitude!)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.setRegion(region, animated: true)
let myAnnotation: MKPointAnnotation = MKPointAnnotation()
myAnnotation.coordinate = CLLocationCoordinate2DMake(userLocation.coordinate.latitude, userLocation.coordinate.longitude);
myAnnotation.title = "Current location"
mapView.addAnnotation(myAnnotation)
}
}
please help me to add delegate method latitude and longitude in locationManager didUpdateLocations
Replace userDidEnterInformation with below code:
func userDidEnterInformation(info: DataEnteredModelSave) {
print("map address viewcontroller data \(info)")
self.pincodeField.text = info.pinCode
self.streetField.text = info.streetField
self.cityField.text = info.cityField
self.latitude = info.zLatitude
self.logitude = info.zLongitude
print("map address viewcontroller data info lat long \(self.latitude) \(self.logitude)")
locationManager.stopUpdatingLocation() //stop updating location when you got data from delegate
let userLocation = CLLocation.init(latitude: latitude!, longitude: logitude!)
let geocoder = CLGeocoder()
geocoder.reverseGeocodeLocation(userLocation) { (placemarks, error) in
if (error != nil){
print("error in reverseGeocode")
}
let placemark = placemarks! as [CLPlacemark]
if placemark.count>0{
let placemark = placemarks![0]
print(placemark.locality!)
print(placemark.administrativeArea!)
print(placemark.country!)
let placemarkDictonary: NSDictionary=placemark.addressDictionary as! NSDictionary
self.pincodeField.text=placemarkDictonary["ZIP"] as? String
self.cityField.text=placemarkDictonary["City"] as? String
self.plotField.text=placemarkDictonary["Name"] as? String
self.streetField.text=placemarkDictonary["Street"] as? String
self.appormentNoField.text=placemarkDictonary["SubThoroughfare"] as? String
self.colonyField.text=placemarkDictonary["SubLocality"] as? String
self.landmarkField.text=placemarkDictonary["SubThoroughfare"] as? String
}
}
let center = CLLocationCoordinate2D(latitude: latitude!, longitude: logitude!)
//Assign data to map again with new location
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01))
mapView.setRegion(region, animated: true)
let myAnnotation: MKPointAnnotation = MKPointAnnotation()
myAnnotation.coordinate = CLLocationCoordinate2DMake(latitude!, logitude!)
myAnnotation.title = "Current location"
mapView.addAnnotation(myAnnotation)
}
I have added comments please check them.
EDIT: As per your second request if you want to show new coordinates on NewZoomAddressViewController first you need to pass coordinates to NewZoomAddressViewController in submitButtonClicked method like:
viewController.latestLocation = CLLocation.init(latitude: self.latitude!, longitude: self.logitude!)
then in NewZoomAddressViewController declare new var
var latestLocation: CLLocation?
and remove other code which is related to user's current location and final code will look like:
import UIKit
import MapKit
import CoreLocation
//import SwiftKeychainWrapper
protocol DataEnteredDelegate: class {
func userDidEnterInformation(info: DataEnteredModelSave)
}
class NewZoomAddressViewController: UIViewController {
#IBOutlet weak var oneBtnContainerView: UIView!
var latitudeZoom: Double?
var logitudeZoom: Double?
weak var delegate: DataEnteredDelegate? = nil
var zipName: String?
var localityName: String?
var sublocalityName: String?
var streetNumber: String?
var streetName: String?
let searchCont = UISearchController(searchResultsController: nil)
let annotation = MKPointAnnotation()
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var addressLabel: UILabel!
let regionInMeters: Double = 10000
var previousLocation: CLLocation?
var latestLocation: CLLocation?
override func viewDidLoad() {
super.viewDidLoad()
print("in Zoom map VC")
mapView.delegate = self
addressLabel.text = "\(self.sublocalityName!) \(localityName!) \(self.zipName!)"
centerViewOnUserLocation()
}
#IBAction func backBtn(_ sender: Any) {
self.navigationController?.popViewController(animated: true)
}
override func viewWillAppear(_ animated: Bool) {
self.navigationController?.navigationBar.isHidden=true
}
var viewController: UIViewController?
#IBAction func confirmBtn(_ sender: Any) {
guard
let zipName = zipName,
let sublocalityName = sublocalityName,
let localityName = localityName,
let lnatZ = latitudeZoom,
let longZ = logitudeZoom
else { return }
let enteredData = DataEnteredModelSave(pinCode: zipName, streetField: sublocalityName, cityField: localityName, zLatitude: lnatZ, zLongitude: longZ)
delegate?.userDidEnterInformation(info: enteredData)
self.navigationController?.popViewController(animated: true)
}
func centerViewOnUserLocation() {
if let location = latestLocation {
let region = MKCoordinateRegion.init(center: location.coordinate, latitudinalMeters: regionInMeters, longitudinalMeters: regionInMeters)
mapView.setRegion(region, animated: true)
}
}
func getCenterLocation(for mapView: MKMapView) -> CLLocation {
latitudeZoom = mapView.centerCoordinate.latitude
logitudeZoom = mapView.centerCoordinate.longitude
print("coordinates from zoom in func \(latitudeZoom), \(logitudeZoom)")
return CLLocation(latitude: latitudeZoom!, longitude: logitudeZoom!)
//print(CLLocation.self)
}
}
extension NewZoomAddressViewController: CLLocationManagerDelegate, UISearchBarDelegate {
// MARK:- Search Address
#IBAction func searchLocationButton(_ sender: Any) {
// let searchCont = UISearchController(searchResultsController: nil)
searchCont.searchBar.delegate = self
searchCont.searchBar.backgroundColor = .blue
present(searchCont, animated:true, completion:nil)
}
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
searchBar.resignFirstResponder()
dismiss(animated: true, completion: nil)
//create the search request
let searchReq = MKLocalSearch.Request()
searchReq.naturalLanguageQuery = searchBar.text
let activeSearch = MKLocalSearch(request: searchReq)
activeSearch.start { (response, error) in
UIApplication.shared.endIgnoringInteractionEvents()
if response == nil{
print("error")
}
else{
//remove annotation
//let annotations = self.mapView.annotations
// self.mapView.removeAnnotation(annotations as! MKAnnotation)
//getting data
let lat = response?.boundingRegion.center.latitude
let long = response?.boundingRegion.center.longitude
//create annotation
//let annotation = MKPointAnnotation()
self.annotation.title = searchBar.text
self.annotation.coordinate = CLLocationCoordinate2DMake(lat!, long!)
self.mapView.addAnnotation(self.annotation)
//zooming annotation
let coordinate: CLLocationCoordinate2D = CLLocationCoordinate2DMake(lat!, long!)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
self.mapView.setRegion(region, animated: true)
// Add below code to get search address
let geoCoder = CLGeocoder()
let location = CLLocation(latitude: lat!, longitude: long!)
geoCoder.reverseGeocodeLocation(location, completionHandler:
{
placemarks, error -> Void in
// Place details
guard let placeMark = placemarks?.first else { return }
// Location name
self.zipName = placeMark.postalCode
self.localityName = placeMark.locality
self.sublocalityName = placeMark.subLocality
self.streetNumber = placeMark.subThoroughfare
self.streetName = placeMark.thoroughfare
})
}
}
}
}
extension NewZoomAddressViewController: MKMapViewDelegate {
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
let center = getCenterLocation(for: mapView)
let geoCoder = CLGeocoder()
guard let previousLocation = self.latestLocation else { return }
guard center.distance(from: previousLocation) > 50 else { return }
self.previousLocation = center
let userLocation :CLLocation = center as CLLocation
latitudeZoom = userLocation.coordinate.latitude
logitudeZoom = userLocation.coordinate.longitude
print("snajxhdwuidhwiuqhdxiqwjmdio \(latitudeZoom), \(logitudeZoom)")
geoCoder.reverseGeocodeLocation(center) { [weak self] (placemarks, error) in
guard let self = self else { return }
if let _ = error {
//TODO: Show alert informing the user
return
}
guard let placemark = placemarks?.first else {
//TODO: Show alert informing the user
return
}
self.streetNumber = placemark.subThoroughfare ?? ""
self.streetName = placemark.thoroughfare ?? ""
print("street number of zoom map \(self.streetName)")
self.localityName = placemark.locality ?? ""//locality
self.sublocalityName = placemark.subLocality ?? ""//locality
self.zipName = placemark.postalCode ?? ""//locality
DispatchQueue.main.async {
self.addressLabel.text = "\(self.streetNumber ?? "") \(self.streetName ?? "") \(self.sublocalityName ?? "") \(self.zipName ?? "") \(self.localityName ?? "")"
print("zzooom map location label \(self.addressLabel.text)")
}
}
}
}

Swift 3 showing Firebase all users profile picture on map as annotation

I want to show user's profile pictures on map. I am storing datas on Firebase as longitude, latitude , photo as url on Firebase. Now, I am getting datas for all users on console. But I could not show these datas as annotation. Profile pictures will show on map according to longitude and latitude. How can I do this. I searched lots of websites and lots of tutorials. I could not find anything. All of shows that adding one picture on map as annotation. I want to do this for all users.`
class HomeTest: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
var ref = Database.database().reference()
var storageRef = Storage.storage().reference()
let manager = CLLocationManager()
var users = [User] ()
override func viewDidLoad() {
super.viewDidLoad()
self.mapView.delegate = self
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
fetchUser()
}
func fetchUser() {
Database.database().reference().child("locations").observe(.childAdded, with: {(snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
user.latitude = dictionary["latitude"] as! Float
user.longitude = dictionary["longitude"] as! Float
user.photo = dictionary["photo"] as! String
//user.username = dictionary["username"] as! String
print(user.latitude, user.longitude, user.photo)
self.users.append(user)
DispatchQueue.main.async(execute: {
// ???
})
}
} , withCancel: nil)
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations [0]
let myLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake(location.coordinate.latitude, location.coordinate.longitude)
let span:MKCoordinateSpan = MKCoordinateSpanMake(0.020,0.020)
let region:MKCoordinateRegion = MKCoordinateRegionMake(myLocation,span)
self.mapView.setRegion(region, animated: true)
self.mapView.isZoomEnabled = true
self.mapView.isScrollEnabled = true
self.mapView.showsUserLocation = true
}
}

Converting Parse PFGeoPoint into an annotation on the map

I am trying to convert a saved PFGeopoint objects in Parse server into an annotation but i can't seem to figure it out and i don't know what's wrong.
I tried to apply the code from this question : Converting Parse GeoPoint into a CLLocation in Swift but i still couldn't figure it out.
Here is my Code :
import UIKit
import MapKit
import CoreLocation
import Parse
class MapVC: UIViewController, MKMapViewDelegate {
fileprivate let locationManager = CLLocationManager()
fileprivate var startedLoadingPOIs = false
fileprivate var places = [Place]()
var descLocation: PFGeoPoint = PFGeoPoint()
var mapHasCenteredOnce = false
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
mapView.delegate = self
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
locationManager.requestWhenInUseAuthorization()
mapView.userTrackingMode = MKUserTrackingMode.followWithHeading
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
var annotationView: MKAnnotationView?
if annotation.isKind(of: MKUserLocation.self) {
annotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: "User")
annotationView?.image = UIImage(named: "loc.png")
}
return annotationView
}
}
extension MapVC: CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
//1
if locations.count > 0 {
let location = locations.last!
print("Accuracy: \(location.horizontalAccuracy)")
//2
if location.horizontalAccuracy < 100 {
//3
manager.stopUpdatingLocation()
let span = MKCoordinateSpan(latitudeDelta: 0.014, longitudeDelta: 0.014)
let region = MKCoordinateRegion(center: location.coordinate, span: span)
mapView.region = region
if !startedLoadingPOIs {
startedLoadingPOIs = true
let loader = PlacesLoader()
loader.loadPOIS(location: location, radius: 1000) { placesDict, error in
if let dict = placesDict {
let query = PFQuery(className: "posts")
if let latitude = (PFUser.current()?["location"] as AnyObject).latitude {
if let longitude = (PFUser.current()?["location"] as AnyObject).longitude {
let geoPoint = PFGeoPoint(latitude: latitude, longitude: longitude)
query.whereKey("postLocation", nearGeoPoint: geoPoint, withinKilometers: 1)
}
}
query.findObjectsInBackground { (objects: [PFObject]?, error: Error?) in
if error == nil {
for object in objects! {
let pfObject = object as PFObject
let caption = pfObject["title"] as! String
self.descLocation = object["postLocation"] as! PFGeoPoint
let latitude: CLLocationDegrees = self.descLocation.latitude
let longitude: CLLocationDegrees = self.descLocation.longitude
let location = CLLocation(latitude: latitude, longitude: longitude)
let place = Place(location: location, name: caption )
self.places.append(place)
let annotation = PlaceAnnotation(location: place.location!.coordinate, title: place.placeName)
DispatchQueue.main.async {
self.mapView.addAnnotation(annotation)
}
}
}
}
}
}
}
}
}
}
}
I just had two uanessacry lines that blocked the operation, removed them and it worked for me.
loader.loadPOIS(location: location, radius: 1000) { placesDict, error in
if let dict = placesDict {

How to find the user's location in swift?

Hello I am developing an application for ios and one of it's functions has to find the user's current location. Here is my code:
import UIKit
import MapKit
import CoreLocation
import SwiftyJSON
struct City {
let name : String
let location : CLLocation
let description :String
let imageName : String
func distanceTo(location:CLLocation) -> Int
{
let distanceMeters = location.distanceFromLocation(self.location)
let distanceKilometers = distanceMeters / 1000.00
return Int(round(100 * distanceKilometers) / 100)
}
}
class FirstViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var LabelTest: UILabel!
#IBOutlet weak var Slider: UISlider!
#IBOutlet weak var LabelValueSlider: UILabel!
var MySliderCurrentValue = Double()
var manager = CLLocationManager()
var userLoc: CLLocationCoordinate2D!
{
willSet{
self.orderCitysByProximity()
self.filterCitysByProximity(Int(self.Slider.value))
self.LocateMe(manager)
}
}
var cities = [City]()
var nearbyCities = [City]()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let path: String = NSBundle.mainBundle().pathForResource("cities", ofType: "json") as String!
let jsonData = NSData(contentsOfFile: path) as NSData!
//let ReadableJSON = JSON ( data:jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil )
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers) as! [String:AnyObject]
for city in jsonObject["cities"] as! [[String:AnyObject]] {
//let coordinates = position["Position"] as! [String:CLLocationDegrees]
let cityName = city["Name"] as! String
let latitude = city["Latitude"] as! Double
let longitude = city["Longitude"] as! Double
let description = city["Description"] as! String
let image = city["Image"] as! String
let location = CLLocation(latitude: latitude, longitude: longitude)
let city = City(name: cityName, location: location,description: description, imageName: image)
cities.append(city)
// print(cities)
}
self.orderCitysByProximity()
self.filterCitysByProximity(Int(self.Slider.value))
} catch let error as NSError {
print(error)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func SliderChange(sender: UISlider) {
let MySliderCurrentValue: String = String(Int(sender.value))
LabelValueSlider.text = MySliderCurrentValue
self.filterCitysByProximity(Int(sender.value))
}
#IBAction func goToTableView()
{
if let tableViewController = self.storyboard?.instantiateViewControllerWithIdentifier("tableViewController") as? TableViewController
{
tableViewController.cities = self.nearbyCities
self.navigationController?.pushViewController(tableViewController, animated: true)
}
}
func filterCitysByProximity(kilometers:Int)
{
self.nearbyCities.removeAll()
for city in self.cities {
if(city.distanceTo(self.userLoc) <= kilometers*2)
{
self.nearbyCities.append(city)
}
}
self.LabelTest.text = "you have \(self.nearbyCities.count) cities nearby"
let OrderedArray = self.nearbyCities.sort({ $0.distanceTo(self.userLoc) < $1.distanceTo(self.userLoc) })
self.nearbyCities = OrderedArray
}
func orderCitysByProximity()
{
let OrderedArray = self.cities.sort({ $0.distanceTo(self.userLoc) < $1.distanceTo(self.userLoc) })
self.cities = OrderedArray
}
#IBAction func LocateMe(sender: AnyObject) {
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userlocation: CLLocation = locations[0] as CLLocation
manager.stopUpdatingLocation()
let location = CLLocationCoordinate2D(latitude: userlocation.coordinate.latitude, longitude: userlocation.coordinate.longitude)
self.userLoc = location
}
}
On the bottom you will see the func locationManager, where I am trying to find the user's current location. Would you please advise me how to start this function so that the app recognise when I type userLoc. userLoc are the coordinations of the user and I have to use them in other functions like func filterCitysByProximity, and the rest, which you can see in the code.
Reason of your problem :-
When you call the delegate of the CLLocationManager in viewDidLoad() it takes some time to retrieve the usersCurrent Location , but even before usersLocation could relay back to you, your functions requiring usersCurrent Location were being triggered as you had called them in viewDidLoad() thus causing the error!
your Code should look like this:-
import UIKit
import MapKit
import CoreLocation
import SwiftyJSON
struct City {
let name : String
let location : CLLocation
let description :String
let imageName : String
func distanceTo(location:CLLocation) -> Int
{
let distanceMeters = location.distanceFromLocation(self.location)
let distanceKilometers = distanceMeters / 1000.00
return Int(round(100 * distanceKilometers) / 100)
}
}
class FirstViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var LabelTest: UILabel!
#IBOutlet weak var Slider: UISlider!
#IBOutlet weak var LabelValueSlider: UILabel!
var MySliderCurrentValue = Double()
var locationManager = CLLocationManager()
var userLoc : CLLocation!
var cities = [City]()
var nearbyCities = [City]()
override func viewDidLoad() {
super.viewDidLoad()
let path: String = NSBundle.mainBundle().pathForResource("cities", ofType: "json") as String!
let jsonData = NSData(contentsOfFile: path) as NSData!
do {
let jsonObject = try NSJSONSerialization.JSONObjectWithData(jsonData!, options: NSJSONReadingOptions.MutableContainers) as! [String:AnyObject]
for city in jsonObject["cities"] as! [[String:AnyObject]] {
//let coordinates = position["Position"] as! [String:CLLocationDegrees]
let cityName = city["Name"] as! String
let latitude = city["Latitude"] as! Double
let longitude = city["Longitude"] as! Double
let description = city["Description"] as! String
let image = city["Image"] as! String
let location = CLLocation(latitude: latitude, longitude: longitude)
let city = City(name: cityName, location: location,description: description, imageName: image)
cities.append(city)
}
} catch let error as NSError {
print(error)
}
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.distanceFilter = kCLDistanceFilterNone
locationManager.requestWhenInUseAuthorization()
locationManager.startMonitoringSignificantLocationChanges()
locationManager.startUpdatingLocation()
if locationManager.respondsToSelector(#selector(locationManager.requestWhenInUseAuthorization)) {
locationManager.requestWhenInUseAuthorization()
locationManager.requestLocation()
}
else {
locationManager.startUpdatingLocation()
}
}
#IBAction func SliderChange(sender: UISlider) {
let MySliderCurrentValue: String = String(Int(sender.value))
LabelValueSlider.text = MySliderCurrentValue
if userLoc != nil{
self.filterCitysByProximity(Int(sender.value), location: userLoc)
}else{
let alertC : UIAlertController = UIAlertController(title: "Iwin", message: "UserLocation Not Updated wait a while", preferredStyle: .Alert)
let okAction : UIAlertAction = UIAlertAction(title: "oK", style: .Default, handler: { (okActn) in
print("User pressed ok")
})
alertC.addAction(okAction)
alertC.popoverPresentationController?.sourceView = view
alertC.popoverPresentationController?.sourceRect = view.frame
self.presentViewController(alertC, animated: true, completion: nil)
}
}
//Segue to .. :-
#IBAction func goToTableView()
{
if let tableViewController = self.storyboard?.instantiateViewControllerWithIdentifier("tableViewController") as? TableViewController
{
tableViewController.cities = self.nearbyCities
print(nearbyCities)
self.navigationController?.pushViewController(tableViewController, animated: true)
}
}
#IBAction func LocateMe(sender: AnyObject) {
}
//Class Functions call :-
func filterCitysByProximity(kilometers:Int, location: CLLocation)
{
self.nearbyCities.removeAll()
for city in self.cities {
if(city.distanceTo(location) <= kilometers*2)
{
self.nearbyCities.append(city)
}
}
self.LabelTest.text = "you have \(self.nearbyCities.count) cities nearby"
let OrderedArray = self.nearbyCities.sort({ $0.distanceTo(location) < $1.distanceTo(location) })
self.nearbyCities = OrderedArray
}
func orderCitysByProximity(location: CLLocation)
{
let OrderedArray = self.cities.sort({ $0.distanceTo(location) < $1.distanceTo(location) })
self.cities = OrderedArray
}
//Location Manager Functions :-
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
userLoc = locations[0] as CLLocation
locationManager.stopUpdatingLocation()
print(userLoc)
self.orderCitysByProximity(userLoc)
self.filterCitysByProximity(Int(self.Slider.value), location : userLoc)
}
func locationManager(manager: CLLocationManager, didChangeAuthorizationStatus status: CLAuthorizationStatus) {
if status == .AuthorizedWhenInUse {
print("authorised call came . . . . ")
locationManager.startUpdatingLocation()
}
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError){
print(error.localizedDescription)
locationManager.stopUpdatingLocation()
}
}
Add privacy - location usage description : Result to your info.plist
Also if your didUpdateLocations function doesn't get called
reset your location Services by going into settings->General->Reset
Try google, you will find multiple questions

How to update annotations when in mapview on zoom?

I'm trying to make an app, where you get buses positions from web API. When I got the data, I put annotations on mapview for all of the coordinates i got from API. Then, when annotation is tapped on, I try to hide all the annotations which aren't on the same route as the one clicked. It works fine, but when I zoom out the annotations that weren't in the original region aren't hidden. Is there a way to refresh what is displayed when user zooms on map view?
import UIKit
import MapKit
import MBProgressHUD
import Alamofire
class MapViewController: UIViewController {
//MARK: Properties and Outlets
private var timer: NSTimer?
private lazy var dateFormatter = NSDateFormatter()
private var vehicles = [String: Vehicle]()
private var points = [CLLocationCoordinate2D]()
private let locationManager = CLLocationManager()
private var currentLocation: CLLocation?
#IBOutlet weak var mapView: MKMapView!
//MARK: Actions
#IBAction func getMyLocation(sender: UIBarButtonItem) {
getLocation()
}
//MARK: Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
dateFormatter.locale = NSLocale.currentLocale()
dateFormatter.dateFormat = "HH:mm:ss"
timer = NSTimer.scheduledTimerWithTimeInterval(30, target: self, selector: "fetchVehiclesLocations", userInfo: nil, repeats: true)
fetchVehiclesLocations()
getLocation()
}
//MARK: Get Location
private func getLocation() {
let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .NotDetermined {
locationManager.requestWhenInUseAuthorization()
return
}
if authStatus == .Denied || authStatus == .Restricted {
showLocationServicesDeniedAlert()
return
}
startLocationManager()
}
//MARK: Helper methods
private func showLocationServicesDeniedAlert() {
let alert = UIAlertController(title: "Location Services Disabled", message: "Please enable location services for this app in Settings.", preferredStyle: .Alert)
let okAction = UIAlertAction(title: "OK", style: .Default, handler: nil)
alert.addAction(okAction)
presentViewController(alert, animated: true, completion: nil)
}
private func startLocationManager () {
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters
locationManager.startUpdatingLocation()
showLoadingHUD()
}
}
private func stopLocationManager() {
locationManager.delegate = nil
locationManager.stopUpdatingLocation()
hideLoadingHUD()
}
private func rotateBus() {
UIView.animateWithDuration(1.0, delay: 0, options: .CurveLinear, animations: {
for (id, _) in self.vehicles {
if self.vehicles[id]!.lastPosition != nil {
let annotationView = self.mapView.viewForAnnotation(self.vehicles[id]!.annotation!)
let currentLocationPoint = self.mapView.convertCoordinate(self.vehicles[id]!.lastPosition!, toPointToView: self.mapView)
let destinationPoint = self.mapView.convertCoordinate(self.vehicles[id]!.coordinates, toPointToView: self.mapView)
let yDiff = currentLocationPoint.y - destinationPoint.y
let xDiff = destinationPoint.x - currentLocationPoint.x
let arcTan = atan(yDiff / xDiff)
var angle = CGFloat(M_PI / 2) - arcTan
if xDiff < 0 {
angle = angle + CGFloat(M_PI)
}
if angle.isNaN || angle == 0.0 {
continue
}
else {
annotationView?.transform = CGAffineTransformMakeRotation(CGFloat(angle))
}
}
}
}, completion: nil)
moveBus()
}
private func moveBus() {
UIView.animateWithDuration(28.0, delay: 0, options: .CurveLinear, animations: {
for(id, _) in self.vehicles {
if self.vehicles[id]!.lastPosition != nil {
self.vehicles[id]!.annotation?.coordinate = self.vehicles[id]!.coordinates
}
}
}, completion: nil)
}
private func createVehicles() {
print(vehicles.count)
for (id, _) in vehicles {
if vehicles[id]?.annotation == nil {
let annotation = BusAnnotation()
annotation.imageName = "bus"
annotation.coordinate = vehicles[id]!.coordinates
annotation.title = id
vehicles[id]?.annotation = annotation
mapView.addAnnotation(annotation)
}
}
print(mapView.annotations.count)
rotateBus()
}
private func drawPolyline() {
let myPolyline = MKPolyline(coordinates: &points, count: points.count)
mapView.addOverlay(myPolyline)
}
//MARK: HUD display methods
private func showLoadingHUD() {
let hud = MBProgressHUD.showHUDAddedTo(mapView, animated: true)
hud.labelText = "Getting Your Location..."
}
private func hideLoadingHUD() {
MBProgressHUD.hideAllHUDsForView(mapView, animated: true)
}
//MARK: Networking
func fetchVehiclesLocations() {
let URL = urlVehiclesLocations + apiKey
if !vehicles.isEmpty {
for (id , _) in vehicles {
vehicles[id]?.lastPosition = vehicles[id]?.coordinates
}
}
Alamofire.request(.GET, URL)
.validate()
.responseJSON {
(request, response, result) in
guard result.isSuccess else {
print("Error while fetching \(result.error!)")
return
}
let value = result.value as? [String: AnyObject]
let responseDict = value?["response"] as? [String: AnyObject]
let array = responseDict?["entity"] as? [[String: AnyObject]]
for var i = 0; i < array?.count; i++ {
let item = array?[i]["vehicle"] as? [String: AnyObject]
let position = item?["position"] as? [String: AnyObject]
let trip = item?["trip"] as? [String: AnyObject]
let vehicle = Vehicle()
vehicle.latitude = position?["latitude"] as! Double
vehicle.longitude = position?["longitude"] as! Double
vehicle.tripId = trip?["trip_id"] as! String
let startTime = trip?["start_time"] as! String
vehicle.startTime = self.dateFormatter.dateFromString(startTime)
let vehicleId = item?["vehicle"] as? [String: AnyObject]
let id = vehicleId?["id"] as! String
if self.vehicles[id] == nil {
self.vehicles[id] = vehicle
}
else {
self.vehicles[id]?.latitude = vehicle.latitude
self.vehicles[id]?.longitude = vehicle.longitude
}
}
self.createVehicles()
}
}
func fetchPointsForTripPolyline() {
let URL = urlTripPolyline + apiKey
Alamofire.request(.GET, URL)
.validate()
.responseJSON {
(request, response, result) in
guard result.isSuccess else {
print("Error while fetching \(result.error!)")
return
}
let value = result.value as! [String: AnyObject]
let responseArray = value["response"] as! [[String: AnyObject]]
for var i = 0; i < responseArray.count; i++ {
let longitude = responseArray[i]["shape_pt_lon"] as! CLLocationDegrees
let latitude = responseArray[i]["shape_pt_lat"] as! CLLocationDegrees
let coordinate = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
self.points.append(coordinate)
}
self.drawPolyline()
}
}
}
extension MapViewController: CLLocationManagerDelegate {
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let newLocation = locations.last!
if newLocation.timestamp.timeIntervalSinceNow < -5 {
return
}
if newLocation.horizontalAccuracy < 0 {
return
}
if newLocation.horizontalAccuracy <= locationManager.desiredAccuracy {
stopLocationManager()
currentLocation = newLocation
let annotation = MKPointAnnotation()
annotation.coordinate = newLocation.coordinate
mapView.addAnnotation(annotation)
}
let center = CLLocationCoordinate2D(latitude: newLocation.coordinate.latitude, longitude: newLocation.coordinate.longitude)
let region = MKCoordinateRegionMakeWithDistance(center, 1000, 1000)
self.mapView.setRegion(region, animated: true)
}
}
extension MapViewController: MKMapViewDelegate {
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if !(annotation is BusAnnotation) {
return nil
}
let reuseId = annotation.title!
var busAnnotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId!)
if busAnnotationView == nil {
busAnnotationView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
busAnnotationView?.canShowCallout = true
}
else {
busAnnotationView?.annotation = annotation
}
let busAnnotation = annotation as! BusAnnotation
busAnnotationView?.image = UIImage(named: busAnnotation.imageName)
return busAnnotationView
}
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
if overlay is MKPolyline {
let lineView = MKPolylineRenderer(overlay: overlay)
lineView.lineWidth = 3.0
lineView.strokeColor = UIColor.greenColor()
return lineView
}
return MKOverlayRenderer()
}
func hideBuses(tripId: String) {
for (_, vehicle) in vehicles {
if vehicle.tripId != tripId {
let annotationView = mapView.viewForAnnotation(vehicle.annotation!)
annotationView?.hidden = true
}
}
}
func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
let vehicleId = view.annotation?.title!
let tripId = vehicles[vehicleId!]?.tripId
hideBuses(tripId!)
}
}