Swift: Geofencing / geolocations near user location - ios

Problem:
I'm trying to make it so that it uses the user's location all the time and constantly checks to see if it is within 5 miles of the CLLocationCoordinate2D points I have set. If so, it sends a alert if the app is open or a notification if the app is closed.
Useful Information:
In my project I have 4 swift files:
Locations.swift holds the CLLocationCoordinate2D points.
Utilities.swift holds a simple alert.
UserLocation.swift retrieves and updates the user's location
GeoLocationViewController.swift monitors the locations
Note:
Some code may not be in the right place or relevant, I was looking at another project trying to extract relevant code from it to use in my project. Please tell me if you do catch a mistake.
Code:
Locations.swift:
import UIKit
import MapKit
class Locations: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
var radius: CLLocationDistance = 5
let arroyo = CLLocationCoordinate2D (latitude: 33.781327997137595, longitude: -116.46394436519012)
var arroyoCoord: CLLocationCoordinate2D = arroyo
let buddyrogers = CLLocationCoordinate2D (latitude: 33.78051204742721, longitude: -116.46362250010833)
var buddyCoord: CLLocationCoordinate2D = buddyrogers
let chopsticks = CLLocationCoordinate2D (latitude: 33.815995425565184, longitude: -116.44107442645873)
let colorfulfountain = CLLocationCoordinate2D (latitude: 33.80443304398751, longitude: -116.45723923544313)
let diamond = CLLocationCoordinate2D (latitude: 33.80216859530781, longitude: -116.45711048941041)
let dinahshore = CLLocationCoordinate2D (latitude: 33.806554795852996, longitude: -116.47734507421876)
let fountoflife = CLLocationCoordinate2D (latitude: 33.78075282028137, longitude: -116.46407847564086)
let fountains = CLLocationCoordinate2D (latitude: 33.780141969313235, longitude: -116.46346156756744)
let historicphoto = CLLocationCoordinate2D (latitude: 33.78130570353292, longitude: -116.46389072100982)
let holistic = CLLocationCoordinate2D (latitude: 33.781338029257775, longitude: -116.46408249895438)
let hollywoodheroes = CLLocationCoordinate2D (latitude: 33.78095792254918, longitude: -116.45820483068849)
let indiangathering = CLLocationCoordinate2D (latitude: 33.78136366689296, longitude: -116.46371905963287)
let indianwomen = CLLocationCoordinate2D (latitude: 33.78622660767695, longitude: -116.45820483068849)
let cathedrals = CLLocationCoordinate2D (latitude: 33.844502990031124, longitude: -116.45834321534426)
let firehouse = CLLocationCoordinate2D (latitude: 33.78103817982461, longitude: -116.46700744788512)
let perfectunion = CLLocationCoordinate2D (latitude: 33.778193459376865, longitude: -116.45877843062743)
let lizards = CLLocationCoordinate2D (latitude: 33.78104263855992, longitude: -116.46340792338714)
let cactus = CLLocationCoordinate2D (latitude: 33.782598723009976, longitude: -116.46699671904906)
let swisscheese = CLLocationCoordinate2D (latitude: 33.78121541437478, longitude: -116.46472086469993)
let newbeginning = CLLocationCoordinate2D (latitude: 33.78049421237406, longitude: -116.46463101069793)
let thunderbolt = CLLocationCoordinate2D (latitude: 33.80140187863324, longitude: -116.46646603445436)
let tictoc = CLLocationCoordinate2D (latitude: 33.80156235478469, longitude: -116.45524367193605)
let wheeloftime = CLLocationCoordinate2D (latitude: 33.815987530910135, longitude: -116.45892863433227)
let artevita = CLLocationCoordinate2D (latitude: 33.7826633, longitude: -116.46041969999999)
let coachellaart = CLLocationCoordinate2D (latitude: 33.78012700000001, longitude: -116.46571840000001)
let colinfisher = CLLocationCoordinate2D (latitude: 33.7819228, longitude: -116.46002010000001)
let garycreative = CLLocationCoordinate2D (latitude: 33.782660, longitude: -116.462141)
let lesliejean = CLLocationCoordinate2D (latitude: 33.78404799999999, longitude: -116.4635222)
let rebeccafine = CLLocationCoordinate2D (latitude: 33.782487, longitude: -116.460564)
let agnes = CLLocationCoordinate2D (latitude: 33.77571242620008, longitude: -116.46372063254091)
let willardprice = CLLocationCoordinate2D (latitude: 33.77489419346815, longitude: -116.46667910908434)
let adobe = CLLocationCoordinate2D (latitude: 33.77479870632753, longitude: -116.46673050629039)
let valsamuelson = CLLocationCoordinate2D (latitude: 33.76802162366799, longitude: -116.46920998147584)
let gallito = CLLocationCoordinate2D (latitude: 33.7794358, longitude: -116.4612692)
let townsquare = CLLocationCoordinate2D (latitude: 33.7810365, longitude: -116.46464559999998)
let ocotillo = CLLocationCoordinate2D (latitude: 33.805963, longitude: -116.46349980000002)
let century = CLLocationCoordinate2D (latitude: 33.8269913, longitude: -116.4424588)
let denniskeat = CLLocationCoordinate2D (latitude: 33.8304982, longitude: -116.45744730000001)
let memorial = CLLocationCoordinate2D (latitude: 33.78318512716751, longitude: -116.46681405767208)
let patriot = CLLocationCoordinate2D (latitude: 33.8019902897174, longitude: -116.44000872473146)
let panorama = CLLocationCoordinate2D (latitude: 33.83861734636407, longitude: -116.46799619895023)
let secondst = CLLocationCoordinate2D (latitude: 33.78069442561766, longitude: -116.45910418200071)
let dogpark = CLLocationCoordinate2D (latitude: 33.7804269, longitude: -116.46041309999998)
}
}
Utilities.swift:
import UIKit
import MapKit
func showSimpleAlertWithTitle(title: String!, message: String, viewController: UIViewController) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
alert.addAction(action)
viewController.presentViewController(alert, animated: true, completion: nil)
}
UserLocation.swift:
import UIKit
import CoreLocation
class UserLocation: UIViewController, CLLocationManagerDelegate {
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
if (CLLocationManager.locationServicesEnabled()) {
locationManager = CLLocationManager()
locationManager.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestAlwaysAuthorization()
locationManager.startUpdatingLocation()
}
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
}
}
GeoLocationViewController.swift:
import UIKit
import CoreLocation
class GeoLocationViewController: UIViewController, CLLocationManagerDelegate {
let locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
// Do any additional setup after loading the view.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func regionWithGeotification(geotification: Locations) -> CLCircularRegion {
// 1
let region = CLCircularRegion(center: geotification.coordinate, radius: geotification.radius, identifier: geotification.identifier)
// 2
region.notifyOnEntry = (geotification.eventType == .OnEntry)
region.notifyOnExit = !region.notifyOnEntry
return region
}
func startMonitoringGeotification(geotification: Locations) {
// 1
if !CLLocationManager.isMonitoringAvailableForClass(CLCircularRegion) {
showSimpleAlertWithTitle("Error", message: "Geofencing is not supported on this device!", viewController: self)
return
}
// 2
if CLLocationManager.authorizationStatus() != .AuthorizedAlways {
showSimpleAlertWithTitle("Warning", message: "Your geotification is saved but will only be activated once you grant permission to access the device location.", viewController: self)
}
// 3
let region = regionWithGeotification(geotification)
// 4
locationManager.startMonitoringForRegion(region)
}
func stopMonitoringGeotification(geotification: Locations) {
for region in locationManager.monitoredRegions {
if let circularRegion = region as? CLCircularRegion {
if circularRegion.identifier == geotification.identifier {
locationManager.stopMonitoringForRegion(circularRegion)
}
}
}
}
func locationManager(manager: CLLocationManager, monitoringDidFailForRegion region: CLRegion?, withError error: NSError) {
print("Monitoring failed for region with identifier: \(region!.identifier)")
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("Location Manager failed with the following error: \(error)")
}
}

First and foremost, change back startMonitoringGeotification(), regionWithGeotification(), and stopMonitoringGeotification() to take in a Geotification like the Ray Wenderlich tutorial. Make sure you have added the file Geotification.swift from his starter code to your project.
Also, make sure your Main.storyboard launches your ViewController. Without this step, none of your code will run.
1) redefine your Locations class more simply in Locations.swift:
import UIKit
import MapKit
class Locations {
static let locations:[String:CLLocationCoordinate2D] = [
"buddyrogers" : CLLocationCoordinate2D(latitude: 33.815995425565184, longitude: -116.44107442645873),
"diamond" : CLLocationCoordinate2D(latitude: 33.802168595307814, longitude: -116.45711048941041),
.
. // add your locations
.
]
}
}
like the #hungry-yeti suggested
2) You can define showSimpleAlertWithTitle() in your GeotificationViewController class. Try calling it in your ViewDidLoad() to test it. You can now delete Utilities.swift.
3) I think you can ignore/remove UserLocation.swift, this seems unnecessary
4) Put this code inside GeotificationViewController's ViewDidLoad:
let radius = CLLocationDistance(8046.72) // 5 miles in meters
for location in Locations.locations {
let g = Geotification(coordinate: location.1, radius: radius, identifier: location.0, note: "test", eventType: EventType.OnEntry)
startMonitoringGeotification(g)
}
5) I hope this helps and simplifies your code. Party on, reply here if you have any issues.

It looks like you're using the Ray Wenderlich tutorial. That's a good one, I found it very useful too.
First off, the unit for CLLocationDistance is meters so the code you have specifies a radius of 5 meters which won't be quite as useful as you may hope; a value of 8046.72 is closer to 5 miles.
Regarding the specific error, Locations is the class that you stuffed all CLLocationCoordinate2D values in, it certainly does not have any member called coordinate. If you're using the tutorial I'm thinking of you will need to load those coords into instances of the Geotification class.
Here is some untested code:
// Load the various coords into an array:
var locations:[(note:String, coords:CLLocationCoordinate2D)] = []
locations +=[(note: "arroyo", CLLocationCoordinate2D( latitude: 33.781327997137595, longitude: -116.46394436519012)]
locations +=[(note: "buddyrogers", CLLocationCoordinate2D( latitude: 33.78051204742721, longitude: -116.46362250010833)]
// ...
let radius = 8000 // ~5 miles rounded to nearest km
// Load the locations into geotifications:
for location in locations {
let geotification = Geotification(coordinate: location.cords, radius: radius, identifier: NSUUID().UUIDString, note: location.note, eventType: EventType.OnEnter)
startMonitoringGeotification(geotification)
}
Now bear in mind that there is a hard limit of 20 monitored regions per app, so if you have more than that you will need to dynamically determine the nearest 20 regions and then monitor those regions.

Multiple GeoFencing with AppleMap In Xcode 12.3(Swift 5) 100% Working
import UIKit
import MapKit
import CoreLocation
struct GeotificationData {
var lat : String?
var long : String?
}
class AppleMapVC: UIViewController {
#IBOutlet weak var mapView: MKMapView!
lazy var locationManager = CLLocationManager()
var arrGeoFenceData = [GeotificationData]()
//MARK:- VIEW CONTROLLER LIFE CYCLE METHOD
override func viewDidLoad() {
super.viewDidLoad()
title = "GeoFence"
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (granted, error) in }
if CLLocationManager.locationServicesEnabled() {
locationManager.delegate = self
locationManager.requestAlwaysAuthorization()
locationManager.desiredAccuracy = kCLLocationAccuracyBest //optimize power performanc Battery
locationManager.startUpdatingLocation()
arrGeoFenceData = [GeotificationData(lat: "21.7469", long: "74.1240"),
GeotificationData(lat: "21.1702", long: "72.8311"),
GeotificationData(lat: "19.9975", long: "73.7898"),
GeotificationData(lat: "20.1738", long: "72.7640"),
GeotificationData(lat: "19.0760", long: "72.8777"),
GeotificationData(lat: "18.5204", long: "73.8567")]
}
getGeoFencing()
}
//show notification
func showNotification(title:String, message:String) {
let content = UNMutableNotificationContent()
content.title = title
content.body = message
content.badge = 1
content.sound = .default
let request = UNNotificationRequest(identifier: "notifi", content: content, trigger: nil)
UNUserNotificationCenter.current().add(request, withCompletionHandler: nil)
}
func monitorRegionAtLocation(center: CLLocationCoordinate2D, identifier: String ) {
// Make sure the devices supports region monitoring.
if CLLocationManager.isMonitoringAvailable(for: CLCircularRegion.self) {
// Register the region.
let maxDistance = CLLocationDistance(30000)
let region = CLCircularRegion(center: center,
radius: maxDistance, identifier: identifier)
region.notifyOnEntry = true
region.notifyOnExit = false
let circle = MKCircle(center: center, radius: maxDistance)
mapView.addOverlay(circle)
locationManager.startMonitoring(for: region)
}
}
func getGeoFencing() {
for item in arrGeoFenceData {
print("Your location with lat and long :- \(item)")
let cordi = CLLocationCoordinate2D(latitude: Double(item.lat!)!, longitude: Double(item.long!)!)
monitorRegionAtLocation(center: cordi, identifier: "Geofence")
}
}
//MARK:- UIBUTTON CLICKED
#IBAction func btnRotationClicked(_ sender: Any) {
mapView.setUserTrackingMode(.followWithHeading, animated: true)
}
}
//MARK:- LOCATIONMANAGER DELEGATE METHOD FOR UPDATE LOCATION
extension AppleMapVC : CLLocationManagerDelegate {
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
if let location = locations.first {
locationManager.stopUpdatingLocation()
// locationManager.startUpdatingLocation()
render(location)
}
}
func locationManager(_ manager: CLLocationManager, didEnterRegion region: CLRegion) {
let alert = UIAlertController.init(title: "You enter in location", message: "enter in geofence", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
showNotification(title: "You entered in geofence", message: "Welcome")
}
func locationManager(_ manager: CLLocationManager, didExitRegion region: CLRegion) {
let alert = UIAlertController.init(title: "You exit in location", message: "exit in geofence", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
showNotification(title: "You exit in geofence", message: "come again")
}
func render(_ location: CLLocation) {
let coordinate = CLLocationCoordinate2D(latitude: location.coordinate.latitude, longitude: location.coordinate.longitude)
let span = MKCoordinateSpan(latitudeDelta: 0.1, longitudeDelta: 0.1)
let region = MKCoordinateRegion(center: coordinate, span: span)
mapView.setRegion(region, animated: true)
mapView.showsUserLocation = true
// let pin = MKPointAnnotation()
// pin.coordinate = coordinate
// mapView.addAnnotation(pin)
}
}
//MARK:- MKMAPVIEW DELEGATE METHOD
extension AppleMapVC : MKMapViewDelegate {
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
guard let circleOverlay = overlay as? MKCircle else {
return MKOverlayRenderer()
}
let circleRender = MKCircleRenderer(circle: circleOverlay)
circleRender.strokeColor = .red
circleRender.fillColor = .red
circleRender.alpha = 0.4
return circleRender
}
}

Related

swift 4 Annotation from json not visible until user drags on map

I am having problems showing the annotations on the map. They only show when I move or drag the map.
I tried to follow tutorial on youtube and also one of the questions which is c sharp
Please can sone one help .. here is the code
Here I created a class for the annotation
class customPin: NSObject, MKAnnotation {
var coordinate: CLLocationCoordinate2D
var title: String?
var subtitle: String?
init(pinTitle:String, pinSubTitle:String, location:CLLocationCoordinate2D) {
self.title = pinTitle
self.subtitle = pinSubTitle
self.coordinate = location
}}
class ViewController: UIViewController, CLLocationManagerDelegate {
#IBOutlet weak var mapView: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
self.locationManager.requestWhenInUseAuthorization()
//json show the list of the parks
pipiCanList()
//show location Barcelona
let location = CLLocationCoordinate2D(latitude: 41.3851 , longitude:2.1734)
let region = MKCoordinateRegion(center: location, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
self.mapView.setRegion(region, animated: true)
self.mapView.delegate = self
}
get the json information
func pipiCanList(){
let url = "http://bluewave.lk/Apps/pipiCan/Api/read.php";
let urlObj = URL(string:url);
URLSession.shared.dataTask(with: urlObj!) {(data, response, error) in
do{
let pipiCans = try JSONDecoder().decode([pipiCanDBList].self, from: data!)
for pipiCan in pipiCans{
let Latitude = (pipiCan.ParkLatitude! as NSString).doubleValue
let Longitude = (pipiCan.ParkLongitude! as NSString).doubleValue
let location = CLLocationCoordinate2D(latitude: Latitude, longitude: Longitude)
//add to
let pin = customPin(pinTitle: pipiCan.ParkName!, pinSubTitle: pipiCan.Area!, location: location)
self.mapView.addAnnotation(pin)
}
} catch{
print ("Error - cannot get list")
}
}.resume()
}
}
You need
DispatchQueue.main.async {
let pin = customPin(pinTitle: pipiCan.ParkName!, pinSubTitle: pipiCan.Area!, location: location)
self.mapView.addAnnotation(pin)
}
As URLSession.shared.dataTask callback is in a background thread and you should access UIKit elements like mapView in the main thread You can also do
self.mapView.showAnnotations(self.mapView.annotations, animated: true)
after the for loop to show all added annotations also keep in mind you set a region here
let location = CLLocationCoordinate2D(latitude: 41.3851 , longitude:2.1734)
let region = MKCoordinateRegion(center: location, span: MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05))
that the response may be with far location values than the above region

Locations tracker icon not showing up on map

Currently I'm setting up location services but for some strange reason the tracker icon isn't appearing:
I know it's working because if I add a pin the pin shows up correctly:
I'm not sure why the tracker isn't showing up, here is the code:
#IBOutlet weak var map: MKMapView!
let locationsManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
locationsManager.delegate = self
locationsManager.desiredAccuracy = kCLLocationAccuracyBest // sets to best location accuracy
locationsManager.requestWhenInUseAuthorization()// requests user location when app is opened
locationsManager.startUpdatingLocation()// updates user location
}
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let userLocation: CLLocation = locations[0]
let latitude: CLLocationDegrees = userLocation.coordinate.latitude
let longitude: CLLocationDegrees = userLocation.coordinate.longitude
let latDelta: CLLocationDegrees = 0.05
let longDelta: CLLocationDegrees = 0.05
let span: MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)
let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude,longitude)
let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)
map.setRegion(region, animated: true)
let pin = MKPointAnnotation()
pin.coordinate.latitude = userLocation.coordinate.latitude
pin.coordinate.longitude = userLocation.coordinate.longitude
pin.title = "My current location"
map.addAnnotation(pin)
}
You need to set the property showsUsersLocation to true. https://developer.apple.com/reference/mapkit/mkmapview/1452682-showsuserlocation
MKMapView can display the user location and track user location for you:
map.showsUserLocation = true
map.userTrackingMode = .follow
There is no need to implement your own location tracking delegate method.
Nevermind, figured it out. In viewDidload():
map.showsUserLocation = true

MKPolyLine isn't showing up on iOS app in Swift 2.0

I'm creating a sort of direction/GPS app and so far everything has been sort of easy.
I've figured out how to find the user's location (with their permission of course)
I've managed to allow them to set a destination in a quick easy way
However, I've run into a small issue. What I want is for the user to select their destination on the screen and the app will give them the fastest way to arrive there.
Here's my ViewController:
class ViewController: UIViewController,MKMapViewDelegate,CLLocationManagerDelegate {
#IBOutlet var mapOfMaps: MKMapView!
let locationManager = CLLocationManager()
var center:CLLocationCoordinate2D!
var SourcePM:MKPlacemark!
let sourcePlacemark: MKPlacemark! = nil
override func viewDidLoad() {
super.viewDidLoad()
self.locationManager.delegate = self
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapOfMaps.showsUserLocation = true
let sourceAnnotation = MKPointAnnotation()
if let location = locationManager.location {
sourceAnnotation.coordinate = location.coordinate
}
let longPress = UILongPressGestureRecognizer(target: self, action: #selector(CardioViewController.action(_:)))
longPress.minimumPressDuration = 1.0
mapOfMaps.addGestureRecognizer(longPress)
//directionRequest
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
let location = locations.last
center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.003, longitudeDelta: 0.003))
self.mapOfMaps.setRegion(region, animated: true)
self.locationManager.stopUpdatingLocation()
SourcePM = MKPlacemark(coordinate: center, addressDictionary: nil)
}
func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
print("ERROr " + error.localizedDescription)
}
func action(gestureRecognizer:UIGestureRecognizer) {
let touchPoint = gestureRecognizer.locationInView(self.mapOfMaps)
let newCoord:CLLocationCoordinate2D = mapOfMaps.convertPoint(touchPoint, toCoordinateFromView: self.mapOfMaps)
let newAnotation = MKPointAnnotation()
newAnotation.coordinate = newCoord
newAnotation.title = "Your Destination"
mapOfMaps.addAnnotation(newAnotation)
let anotPM = MKPlacemark(coordinate: newAnotation.coordinate, addressDictionary: nil)
let source = MKMapItem(placemark: SourcePM)
let dstn = MKMapItem(placemark: anotPM)
let directionRequest = MKDirectionsRequest()
directionRequest.source = source
directionRequest.destination = dstn
directionRequest.transportType = .Automobile
// Calculate the direction
let directions = MKDirections(request: directionRequest)
// 8.
directions.calculateDirectionsWithCompletionHandler() {
(response, error) in
if(error == nil && response != nil) {
for route in response!.routes {
var r: MKRoute = route as! MKRoute
self.mapOfMaps.addOverlay(r.polyline, level: MKOverlayLevel.AboveRoads)
}
}
let route = response!.routes[0]
self.mapOfMaps.addOverlay((route.polyline), level: MKOverlayLevel.AboveLabels)
let rect = route.polyline.boundingMapRect
self.mapOfMaps.setRegion(MKCoordinateRegionForMapRect(rect), animated: true)
}
}
func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
let renderer = MKPolylineRenderer(overlay: overlay)
renderer.strokeColor = UIColor.orangeColor()
renderer.alpha = 1
renderer.lineWidth = 4.0
return renderer
}
}
to help walk you through my code. My user will press and hold the destination on the map and the app will add an annotation and it should give the route. However, all that happens is the annotation will be added to the map, and the map will adjust to show both locations(user's location and annotation location) but no route.
This may not be the 'ideal' solution, but it's worth noting that both locationManager functions can't work at the same time. I tried commenting one of the locationManager functions out and low and behold the other worked perfectly

How to calculate the distance between my current location and other Pins in MapView

I am new to Swift and I need to calculate the nearest places around my current location. Would you advice me which function should I use to calculate the distance between my location and the nearest around me. I have to display the distance and the places in the app,so that the user can choose which one fits best for him.I think I should use latitude and longitude coordinates which can be compared with mine. I also found out that I have to use distanceFromLocation , but I do not know how and I would be glad if someone provide me with an example which I can use for my code.
My code so far is:
class ViewThree: UIViewController, CLLocationManagerDelegate{
#IBOutlet weak var SegmentControl: UISegmentedControl!
#IBOutlet weak var Mapview: MKMapView!
var manager = CLLocationManager()
var receiveImeNaSladkarnica: String = ""
var KordaA: String = ""
var KordaB: String = ""
var PodImeNaObekt: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let pinLocation: CLLocationCoordinate2D = CLLocationCoordinate2DMake((KordaA as NSString).doubleValue,(KordaB as NSString).doubleValue)
let objectAnn = MKPointAnnotation()
objectAnn.coordinate = pinLocation
objectAnn.title = receiveImeNaSladkarnica
objectAnn.subtitle = PodImeNaObekt
self.Mapview.addAnnotation(objectAnn)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func Directions(sender: AnyObject) {
UIApplication.sharedApplication().openURL(NSURL(string: "http://maps.apple.com/maps?daddr=\((KordaA as NSString).doubleValue),\((KordaB as NSString).doubleValue))")!)
}
#IBAction func MapType(sender: AnyObject) {
if (SegmentControl.selectedSegmentIndex == 0){
Mapview.mapType = MKMapType.Standard
}
if (SegmentControl.selectedSegmentIndex == 1){
Mapview.mapType = MKMapType.Satellite
}
}
#IBAction func LocateMe(sender: AnyObject) {
manager.delegate = self
manager.desiredAccuracy = kCLLocationAccuracyBest
manager.requestWhenInUseAuthorization()
manager.startUpdatingLocation()
Mapview.showsUserLocation = true
}
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)
let span = MKCoordinateSpanMake(0.5, 0.5)
let region = MKCoordinateRegion(center: location, span: span)
Mapview.setRegion(region, animated: true )
}
I had the same scenario with an other app.
Within the CLLocation object, there is an instance function:
func distanceFromLocation(location: CLLocation) -> CLLocationDistance
//Get your two locations that you want to calculate the distance from:
let userLocation: CLLocation = ...
let locationToCompare: CLLocation = ...
// Returned value is in meters
let distanceMeters = userLocation.distanceFromLocation(locationToCompare)
// If you want to round it to kilometers
let distanceKilometers = distanceMeters / 1000.00
// Display it in kilometers
let roundedDistanceKilometers = String(Double(round(100 * distanceKilometers) / 100)) + " km"
UPDATED
For your use case
let locations = ... // All locations you want to compare
for location in locations {
let distanceMeters = userLocation.distanceFromLocation(location)
if distanceMeters > 5000 { // Some distance filter
// Don't display this location
} else {
// Display this location
}
}
MY CODE:
IMPROVED
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)
let span = MKCoordinateSpanMake(0.5, 0.5)
let region = MKCoordinateRegion(center: location, span: span)
Mapview.setRegion(region, animated: true)
let locationStrings = ["42.6977,23.3219","43.6977,24.3219"]
// This array must be an array that contains CLLocation objects
var locations: [CLLocation] = []
// We must retrieve the latitude and longitude from locationStrings array to convert them into CLLocation objects
for locationString in locationStrings {
let location = CLLocation(latitude: <latitude_value>, longitude: <latitude_value>)
locations.append(location)
}
// Then you will be able to enumerate through the array
for location in locations {
let distanceMeters = userLocation.distanceFromLocation(location)
if distanceMeters > 5000 { // Some distance filter
// Don't display this location
} else {
// Display this location
}
}
You can use distanceFromLocation method to get distance
let distance = userlocation.distanceFromLocation(YourPinInMap)
locA = [[CLLocation alloc] initWithLatitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"startLat"]floatValue] longitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"startlong"]floatValue]];
locB = [[CLLocation alloc] initWithLatitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"destLat"]floatValue] longitude:[[[NSUserDefaults standardUserDefaults]valueForKey:#"destLong"]floatValue]];
distance = [locA distanceFromLocation:locB];
where locA and locB are CLLocation type pass the lat long over there

Swift CLLocationDistance error

I am building a learning app where i want to create pins and show the distance between current location and the pin but i get a really weird output
func createPin(){
var coord = CLLocationCoordinate2D(latitude: 51.50, longitude: -0.13)
var coord2 = CLLocation(latitude: coord.latitude, longitude: coord.longitude)
var kilometers:CLLocationDistance = coord2.distanceFromLocation(locNow)
var str = NSString(format: "%.2f", kilometers)
let pin = Annotation(coordinate: coord, title: "LocationAlfa", subtitle: "distance : \(str)" + " meters", dist: kilometers)
map.addAnnotation(pin)
println("\(kilometers)")
}
this is my create pin method and here i get my location distance
func locationManager(manager: CLLocationManager!, didUpdateToLocation newLocation: CLLocation!, fromLocation oldLocation: CLLocation!){
let location = newLocation
let center = CLLocationCoordinate2D(latitude: location!.coordinate.latitude, longitude: location!.coordinate.longitude)
var region: () = centerMapOnLocation(location)
// self.map.setRegion(region, animated: true)
println("Latitude = \(newLocation.coordinate.latitude)")
println("Longitude = \(newLocation.coordinate.longitude)")
locNow = newLocation
}
and this is the shown distance in meters on the map : 5718215.17 (when the pin is made next to the pointed location on the map as the device location)

Resources