iOS 区域监控不工作
iOS Region Monitoring not working
几个月来我一直在做一些 iOS 开发,最近我正在开发一个公交应用程序。
我目前正在模仿公共汽车的运动,并在公共汽车站上设置多个注释。出于测试目的,我只设置了一个公交车站,并试图监控公交车何时进入和退出该区域。
奇怪的是,我的 didStartMonitoringForRegion
方法被完美地调用了,但是 didEnterRegion
和 didExitRegion
方法都没有被调用。每次我运行这个程序,公共汽车几乎都经过了车站而没有提示我。
有人可以向我解释为什么会发生这种情况以及如何解决吗?
let locationManager = CLLocationManager()
var allBusAnnotations = [MKPointAnnotation]()
var summitEastBusStations = [CLLocationCoordinate2D]()
var busStopNames = ["Dix Stadium", "Risman Plaza", "Terrace Drive", "Terrace Drive 2","C-Midway","Theatre Dr.","East Main Street","South Lincoln"]
var radius = 500 as CLLocationDistance
// 0.02 is the best zoom in factor
var mapZoomInFactor : Double = 0.02
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.getBusStop()
self.locationManager.delegate = self
// gets the exact location of the user
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
// gets the user's location only when the app is in use and not background
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
self.setBusStopAnnotations(summitEastBusStations)
// self.mapView.mapType = MKMapType.Satellite
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// sends the latitude and longitude to the Apple Servers then returns the address
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placeMarks: [AnyObject]!, error: NSError!) -> Void in
if error != nil
{
println("Reverse Geocode Failed: " + error.localizedDescription)
return
}
if placeMarks.count > 0
{
// gets the most updated location
let pm = placeMarks.last as! CLPlacemark
let centre = CLLocationCoordinate2D(latitude: manager.location.coordinate.latitude, longitude: manager.location.coordinate.longitude)
// draws a circle in which the map will zoom to
let region = MKCoordinateRegion(center: centre, span: MKCoordinateSpan(latitudeDelta: self.mapZoomInFactor, longitudeDelta: self.mapZoomInFactor))
self.mapView.setRegion(region, animated: true)
self.displayLocationInfo(pm)
// self.distanceToClosestAnnotation(pm)
self.geoFencing()
// YOU CAN IGNORE THIS WHOLE PART. IT'S IRRELEVANT FOR THIS QUESTION
var repeatTimes = 0
var count = 0
while(count <= 7)
{
if count == (self.summitEastBusStations.count - 1)
{
count = 1
++repeatTimes
}
else if repeatTimes == 1
{
count = 0
++repeatTimes
}
else if repeatTimes == 2
{
break
}
self.distanceToBusStop(pm, count: count)
++count
}
}
})
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("Location Manager Failed: " + error.localizedDescription)
}
func locationManager(manager: CLLocationManager!, didStartMonitoringForRegion region: CLRegion!) {
println("The region is monitored")
println("The monitored region is \(region.description)")
}
func locationManager(manager: CLLocationManager!, monitoringDidFailForRegion region: CLRegion!, withError error: NSError!) {
println("Failed to monitor the stated region")
}
func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
println("The bus has entered the region")
}
func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
println("The bus has left the region")
}
func geoFencing()
{
let rismanPlaza = CLLocationCoordinate2D(latitude: 41.1469492, longitude: -81.344068)
var currentBusStop = CLLocation(latitude: rismanPlaza.latitude, longitude: rismanPlaza.longitude)
addRadiusCircle(currentBusStop)
let busStopRegion = CLCircularRegion(center: CLLocationCoordinate2D(latitude: rismanPlaza.latitude, longitude: rismanPlaza.longitude), radius: radius, identifier: busStopNames[1])
if radius > self.locationManager.maximumRegionMonitoringDistance
{
radius = self.locationManager.maximumRegionMonitoringDistance
}
locationManager.startMonitoringForRegion(busStopRegion)
}
// creates the radius around the specified location
func addRadiusCircle(location: CLLocation)
{
self.mapView.delegate = self
var circle = MKCircle(centerCoordinate: location.coordinate, radius: radius)
self.mapView.addOverlay(circle)
}
// performs the actual circle colouring
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!
{
if overlay is MKCircle
{
var circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = UIColor.redColor()
circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circle.lineWidth = 1
return circle
}
else
{
return nil
}
}
请确保 [CLLocationManager regionMonitoringAvailable]
returns YES
和
CLLocationManager.monitoredRegions
包含有效区域。
此外,来自 Apple 文档:
In iOS 6, regions with a radius between 1 and 400 meters work better
on iPhone 4S or later devices. (In iOS 5, regions with a radius
between 1 and 150 meters work better on iPhone 4S and later devices.)
On these devices, an app can expect to receive the appropriate region
entered or region exited notification within 3 to 5 minutes on
average, if not sooner.
和
Apps can expect a notification as soon as the device moves 500 meters
or more from its previous notification. It should not expect
notifications more frequently than once every five minutes. If the
device is able to retrieve data from the network, the location manager
is much more likely to deliver notifications in a timely manner.
我最终改用了 CLRegion.containsCoordinate(location.coordinate)
方法。它的工作方式几乎相同。
一旦对象进入我设置的区域,它就returns为真,从这里我可以知道它何时进入和离开该区域。
您的委托未触发的原因有很多。首先转到目标设置并在功能选项卡中检查是否启用了 BackgroundModes Location Updates。
如果它打开然后尝试检查您当前的位置管理器是否包含您通过检查指定的区域
NSLog(@"Monitored Regions %@",self.locationManager.monitoredRegions);
然后如果用户设备在当前位置(纬度和经度),didEnterRegion: 和 didExitRegion: 代表将不会被触发.使用 didDetermineState: 方法来查找 user/device 是否在当前被监视的区域中。如果是这样, didDetermineState: 将被触发。一旦用户离开区域 didExitRegion: 将被触发。
然后如果委托没有触发然后在委托中使用以下内容找到错误
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(@"Failed to Monitor %@", error);
}
几个月来我一直在做一些 iOS 开发,最近我正在开发一个公交应用程序。 我目前正在模仿公共汽车的运动,并在公共汽车站上设置多个注释。出于测试目的,我只设置了一个公交车站,并试图监控公交车何时进入和退出该区域。
奇怪的是,我的 didStartMonitoringForRegion
方法被完美地调用了,但是 didEnterRegion
和 didExitRegion
方法都没有被调用。每次我运行这个程序,公共汽车几乎都经过了车站而没有提示我。
有人可以向我解释为什么会发生这种情况以及如何解决吗?
let locationManager = CLLocationManager()
var allBusAnnotations = [MKPointAnnotation]()
var summitEastBusStations = [CLLocationCoordinate2D]()
var busStopNames = ["Dix Stadium", "Risman Plaza", "Terrace Drive", "Terrace Drive 2","C-Midway","Theatre Dr.","East Main Street","South Lincoln"]
var radius = 500 as CLLocationDistance
// 0.02 is the best zoom in factor
var mapZoomInFactor : Double = 0.02
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.getBusStop()
self.locationManager.delegate = self
// gets the exact location of the user
self.locationManager.desiredAccuracy = kCLLocationAccuracyBest
// gets the user's location only when the app is in use and not background
self.locationManager.requestWhenInUseAuthorization()
self.locationManager.startUpdatingLocation()
self.mapView.showsUserLocation = true
self.setBusStopAnnotations(summitEastBusStations)
// self.mapView.mapType = MKMapType.Satellite
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
// sends the latitude and longitude to the Apple Servers then returns the address
CLGeocoder().reverseGeocodeLocation(manager.location, completionHandler: { (placeMarks: [AnyObject]!, error: NSError!) -> Void in
if error != nil
{
println("Reverse Geocode Failed: " + error.localizedDescription)
return
}
if placeMarks.count > 0
{
// gets the most updated location
let pm = placeMarks.last as! CLPlacemark
let centre = CLLocationCoordinate2D(latitude: manager.location.coordinate.latitude, longitude: manager.location.coordinate.longitude)
// draws a circle in which the map will zoom to
let region = MKCoordinateRegion(center: centre, span: MKCoordinateSpan(latitudeDelta: self.mapZoomInFactor, longitudeDelta: self.mapZoomInFactor))
self.mapView.setRegion(region, animated: true)
self.displayLocationInfo(pm)
// self.distanceToClosestAnnotation(pm)
self.geoFencing()
// YOU CAN IGNORE THIS WHOLE PART. IT'S IRRELEVANT FOR THIS QUESTION
var repeatTimes = 0
var count = 0
while(count <= 7)
{
if count == (self.summitEastBusStations.count - 1)
{
count = 1
++repeatTimes
}
else if repeatTimes == 1
{
count = 0
++repeatTimes
}
else if repeatTimes == 2
{
break
}
self.distanceToBusStop(pm, count: count)
++count
}
}
})
}
func locationManager(manager: CLLocationManager!, didFailWithError error: NSError!) {
println("Location Manager Failed: " + error.localizedDescription)
}
func locationManager(manager: CLLocationManager!, didStartMonitoringForRegion region: CLRegion!) {
println("The region is monitored")
println("The monitored region is \(region.description)")
}
func locationManager(manager: CLLocationManager!, monitoringDidFailForRegion region: CLRegion!, withError error: NSError!) {
println("Failed to monitor the stated region")
}
func locationManager(manager: CLLocationManager!, didEnterRegion region: CLRegion!) {
println("The bus has entered the region")
}
func locationManager(manager: CLLocationManager!, didExitRegion region: CLRegion!) {
println("The bus has left the region")
}
func geoFencing()
{
let rismanPlaza = CLLocationCoordinate2D(latitude: 41.1469492, longitude: -81.344068)
var currentBusStop = CLLocation(latitude: rismanPlaza.latitude, longitude: rismanPlaza.longitude)
addRadiusCircle(currentBusStop)
let busStopRegion = CLCircularRegion(center: CLLocationCoordinate2D(latitude: rismanPlaza.latitude, longitude: rismanPlaza.longitude), radius: radius, identifier: busStopNames[1])
if radius > self.locationManager.maximumRegionMonitoringDistance
{
radius = self.locationManager.maximumRegionMonitoringDistance
}
locationManager.startMonitoringForRegion(busStopRegion)
}
// creates the radius around the specified location
func addRadiusCircle(location: CLLocation)
{
self.mapView.delegate = self
var circle = MKCircle(centerCoordinate: location.coordinate, radius: radius)
self.mapView.addOverlay(circle)
}
// performs the actual circle colouring
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!
{
if overlay is MKCircle
{
var circle = MKCircleRenderer(overlay: overlay)
circle.strokeColor = UIColor.redColor()
circle.fillColor = UIColor(red: 255, green: 0, blue: 0, alpha: 0.1)
circle.lineWidth = 1
return circle
}
else
{
return nil
}
}
请确保 [CLLocationManager regionMonitoringAvailable]
returns YES
和
CLLocationManager.monitoredRegions
包含有效区域。
此外,来自 Apple 文档:
In iOS 6, regions with a radius between 1 and 400 meters work better on iPhone 4S or later devices. (In iOS 5, regions with a radius between 1 and 150 meters work better on iPhone 4S and later devices.) On these devices, an app can expect to receive the appropriate region entered or region exited notification within 3 to 5 minutes on average, if not sooner.
和
Apps can expect a notification as soon as the device moves 500 meters or more from its previous notification. It should not expect notifications more frequently than once every five minutes. If the device is able to retrieve data from the network, the location manager is much more likely to deliver notifications in a timely manner.
我最终改用了 CLRegion.containsCoordinate(location.coordinate)
方法。它的工作方式几乎相同。
一旦对象进入我设置的区域,它就returns为真,从这里我可以知道它何时进入和离开该区域。
您的委托未触发的原因有很多。首先转到目标设置并在功能选项卡中检查是否启用了 BackgroundModes Location Updates。
如果它打开然后尝试检查您当前的位置管理器是否包含您通过检查指定的区域
NSLog(@"Monitored Regions %@",self.locationManager.monitoredRegions);
然后如果用户设备在当前位置(纬度和经度),didEnterRegion: 和 didExitRegion: 代表将不会被触发.使用 didDetermineState: 方法来查找 user/device 是否在当前被监视的区域中。如果是这样, didDetermineState: 将被触发。一旦用户离开区域 didExitRegion: 将被触发。
然后如果委托没有触发然后在委托中使用以下内容找到错误
- (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error {
NSLog(@"Failed to Monitor %@", error);
}