Swift:用户位置附近的地理围栏/地理位置
Posted
技术标签:
【中文标题】Swift:用户位置附近的地理围栏/地理位置【英文标题】:Swift: Geofencing / geolocations near user location 【发布时间】:2016-05-08 10:33:00 【问题描述】:问题:
我试图让它一直使用用户的位置,并不断检查它是否在我设置的CLLocationCoordinate2D
点的 5 英里范围内。如果是这样,它会在应用程序打开时发送警报,或者在应用程序关闭时发送通知。
有用信息:
在我的项目中,我有 4 个 swift 文件:
Locations.swift 拥有 CLLocationCoordinate2D
点。
Utilities.swift 包含一个简单的警报。
UserLocation.swift 检索并更新用户的位置
GeoLocationViewController.swift 监控位置
注意:
某些代码可能不在正确的位置或不相关,我正在查看另一个项目,试图从中提取相关代码以在我的项目中使用。请告诉我你是否发现了错误。
代码:
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)")
【问题讨论】:
您到底想要什么?你被困在哪里了? @Vishnugondlekar 我希望该应用始终使用用户的位置,并不断检查他们是否在我在 Locations.swift 中列出的位置的 5 英里范围内。我只是不确定我是否有正确的代码来做到这一点。我还从另一个应用程序获取代码。我在let region = CLCircularRegion(center: geotification.coordinate, radius: geotification.radius, identifier: geotification.identifier)
上的 GeoLocationViewController.swift 中有错误我得到“位置”没有成员“坐标”。以及在这条线上:if circularRegion.identifier == geotification.identifier
.
你的应用打开哪个 ViewController?我假设它是GeotificationsViewController
?
@mmarkman 它不会向视图控制器打开。我希望它只是在后台运行。
【参考方案1】:
首先,将startMonitoringGeotification()
、regionWithGeotification()
和stopMonitoringGeotification()
改回Geotification
,就像Ray Wenderlich 教程一样。确保您已将文件 Geotification.swift 从他的起始代码添加到您的项目中。
另外,请确保您的 Main.storyboard 启动您的 ViewController
。如果没有这一步,您的任何代码都不会运行。
1) 在 Locations.swift 中更简单地重新定义您的 Locations
类:
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
.
]
就像@hungry-yeti 建议的那样
2) 您可以在 GeotificationViewController
类中定义 showSimpleAlertWithTitle()
。尝试在您的 ViewDidLoad()
中调用它来测试它。您现在可以删除 Utilities.swift。
3) 我认为你可以忽略/删除 UserLocation.swift,这似乎没有必要
4) 将此代码放入GeotificationViewController
的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) 我希望这有助于并简化您的代码。派对,如果您有任何问题,请在此处回复。
【讨论】:
我在课堂上有一些错误。你有保管箱吗?如果是这样,它的电子邮件是什么?如果你没问题,我可以制作一个示例项目并将其与这些文件一起发送给你,这样你就可以看到错误,而不是我在这里解释它们。一旦他们被修复,你可以把它寄回去。我发现这是一种解决问题的简单方法,就像过去一样。 你能把你的项目发布到 Github 上让其他人学习吗?如果没有,我会做一个 Dropbox 我没有 Github,也不知道怎么用。如果我们现在可以使用 Dropbox,那就太好了,之后我会找到 Github。一旦我们解决了问题,我会将链接发布到 Github。【参考方案2】:您似乎正在使用 Ray Wenderlich 教程。这个不错,我也觉得很好用。
首先,CLLocationDistance 的单位是米,因此您的代码指定半径为 5 米,这并不像您希望的那样有用; 8046.72 的值更接近 5 英里。
关于具体的错误,Locations 是你填充所有 CLLocationCoordinate2D 值的类,它当然没有任何称为坐标的成员。如果您正在使用本教程,我认为您需要将这些坐标加载到 Geotification 类的实例中。
这是一些未经测试的代码:
// 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)
现在请记住,每个应用有 20 个受监控区域的硬性限制,因此,如果您有更多区域,则需要动态确定最近的 20 个区域,然后监控这些区域。
【讨论】:
如何将坐标加载到实例中?【参考方案3】:在 Xcode 12.3(Swift 5) 中使用 AppleMap 进行多重地理围栏 100% 工作
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
【讨论】:
以上是关于Swift:用户位置附近的地理围栏/地理位置的主要内容,如果未能解决你的问题,请参考以下文章