【问题标题】:iOS Region Monitoring not workingiOS 区域监控不起作用
【发布时间】:2015-12-09 11:06:48
【问题描述】:

我已经做了几个月的 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
    }
}

【问题讨论】:

    标签: ios core-location cllocationmanager geofencing clregion


    【解决方案1】:

    请确保[CLLocationManager regionMonitoringAvailable] 返回YES 和 CLLocationManager.monitoredRegions 包含有效区域。

    另外,来自 Apple 文档:

    在 iOS 6 中,半径在 1 到 400 米之间的区域效果更好 在 iPhone 4S 或更高版本的设备上。 (在 iOS 5 中,具有半径的区域 1 到 150 米之间的距离在 iPhone 4S 及更高版本的设备上效果更好。) 在这些设备上,应用程序可以期望接收适当的区域 在 3 到 5 分钟内进入或区域退出通知 平均,如果不是更早的话。

    和

    只要设备移动 500 米,应用就会收到通知 或更多来自其先前的通知。它不应该期望 通知的频率高于每五分钟一次。如果 设备能够从网络中检索数据,位置管理器 更有可能及时发送通知。

    【讨论】:

    • 对于迟到的回复,我深表歉意。我尝试了您建议的所有方法,但仍然无法正常工作。 [CLLocationManager regionMonitoringAvailable] 已弃用,目前使用 CLLocationManager.isMonitoringAvailableForClass()。它返回 true,并且我的受监控区域返回正确的值,但仍未检测到区域进入或退出。
    【解决方案2】:

    我最终改用CLRegion.containsCoordinate(location.coordinate) 方法。它的工作方式几乎相同。

    一旦对象进入我设置的区域,它就会返回 true,从这里我可以知道它何时进入和退出该区域。

    【讨论】:

    • 你能分享一段代码吗?怎么知道什么时候进入和退出方法调用?
    • 这是不久前的事了。如果我记得,由于调用了didStartMonitoringForRegion,我手动使用CLRegion.containsCoordinate 跟踪。因此,当当前坐标在我的区域内时,该方法返回 true,这就是我知道它进入我的区域的方式。该方法将一直返回 true,直到坐标不在该区域内,因此退出该区域。无论哪种方式,你都不应该使用这个 API,因为它有 deprecated
    • 但我没有使用这种区域是否包含坐标。我刚刚为特定的经纬度创建了一个半径为 50 米的 CLRegion。我的方法在输入位置时调用得更好,但是当我距离它给我出口的位置 500 米时,我的退出方法大约需要很多时间。我不明白是什么原因。
    【解决方案3】:

    您的代表没有触发的原因有很多。首先转到目标设置并在功能选项卡中检查 BackgroundModes Location Updates 是否已启用。 如果它打开然后尝试检查您当前的位置管理器是否拥有您指定的区域,方法是检查 NSLog(@"Monitored Regions %@",self.locationManager.monitoredRegions);

    如果用户设备在当前位置(纬度和经度),didEnterRegion: 和 didExitRegion: 代表将不会触发。使用 didDetermineState: 方法来查找用户/设备是否在当前被监控的区域。如果是这样,didDetermineState: 将被触发。一旦用户离开区域 didExitRegion: 就会被触发。

    然后,如果委托未触发,则使用委托中的以下内容查找然后错误 - (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error { NSLog(@"Failed to Monitor %@", error); }

    【讨论】:

      猜你喜欢
      • 2015-02-07
      • 2017-11-29
      • 2011-07-17
      • 1970-01-01
      • 2023-03-26
      • 2013-11-20
      • 2018-05-21
      • 2014-05-23
      • 2014-11-23
      相关资源
      最近更新 更多