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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With