-->

iOS Region Monitoring not working

2019-05-23 09:54发布

问题:

I have been doing some iOS development for a couple of months and recently I am developing a bus app. I am currently mimicking the bus' movements and set up multiple annotations on the bus stops. For test purposes, I have setup just one bus stop and am trying to monitor when the bus has entered this region and exited as well.

Strangely, my didStartMonitoringForRegion method is called perfectly but neither the didEnterRegion nor didExitRegion methods are called. Every time I run the program, the bus pretty much passes the stop without prompting me so.

Could someone explain to me why this is happening and how to resolve it?

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
    }
}

回答1:

Please ensure [CLLocationManager regionMonitoringAvailable] returns YES and CLLocationManager.monitoredRegions contains valid regions.

Also, from Apple documentation:

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.

And

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.



回答2:

I ended up using the CLRegion.containsCoordinate(location.coordinate) method instead. It works pretty much the same way.

Once the object has entered my set region, it returns true and from here I can know when it's entered and exited the region.



回答3:

There are many causes why your delegates are not triggering. First goto target settings and in capabilities tab check whether in BackgroundModes Location Updates is enabled. If it is on then try to check whether your current location manager holds the region you've specified by checking NSLog(@"Monitored Regions %@",self.locationManager.monitoredRegions);

Then if the user device is at current location(Latitude and longitude) the didEnterRegion: and didExitRegion: delegates will not be triggering. Use didDetermineState: method to find whether the user/device is in current region that is moniotred. If it so, didDetermineState: will be triggered. Once the user leaves the region didExitRegion: will be triggered.

Then after also if delegates aren't trigerring then find then error using the following in delegate - (void)locationManager:(CLLocationManager *)manager monitoringDidFailForRegion:(CLRegion *)region withError:(NSError *)error { NSLog(@"Failed to Monitor %@", error); }