2

I am building a feature related to region monitoring while starting region monitoring I am requesting the state as shown below in code. On some of the devices, I am getting region state Unknown all the time. If I switch Wifi On or Off or plug the charger into it. It starts working fine. How can I make it more reliable on a cellular network? Please, note I took all location permissions from the user before making any region monitoring or state request calls.

private func initiateLocationManager() {
    locationManager = CLLocationManager()
    locationManager.delegate = self
    locationManager.distanceFilter = kCLLocationAccuracyBest
    locationManager.requestAlwaysAuthorization()
}

func startMonitoring(alarm: StationAlarm) {
    if LocationManager.sharedInstance.isRegionMonitoringAvailable() {
        let coordinate = CLLocationCoordinate2D(latitude: stationLatitude, longitude: stationLongitude)

        // 1
        let region = CLCircularRegion(center: coordinate, radius: CLLocationDistance(radius * 1000), identifier: alarm.alarmId)

        // 2
        region.notifyOnEntry = true
        region.notifyOnExit = false

        // 4
        locationManager.startMonitoring(for: region)
        Utility.delay(0.1) { [weak self] in
            self?.locationManager.requestState(for: region)
        }

    }
}

func locationManager(_: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
    Log.event("Region State is \(state.rawValue)")
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
kidsid49
  • 1,358
  • 3
  • 18
  • 37
  • See [Apple's recommendation for testing Region Monitoring](https://stackoverflow.com/questions/23866097/ios-geofence-clcircularregion-monitoring-locationmanagerdidexitregion-does-not/47099174#47099174) – mfaani Dec 17 '17 at 10:01
  • @Honey But I am not waiting for entry or exit notification. I simply requested for existing state of the region after, calling start monitoring. – kidsid49 Dec 17 '17 at 12:42
  • Yes but your wifi is off. I just wanted to point out to: "if Wi-Fi is disabled, region monitoring is significantly less accurate." And likely that will cause it to be unknown... – mfaani Dec 17 '17 at 14:27
  • @Honey Even sometimes it happens in Wifi as well. – kidsid49 Dec 17 '17 at 14:45
  • 1. I'm guessing that's because of the quality of the geofence. Did you see the other answers on that linked question? 2. AFAIK you're really not suppose to care about its state, rather just care if it entered/exited a region – mfaani Dec 17 '17 at 18:54
  • I need to tell the user if he/she is already inside the region. – kidsid49 Dec 18 '17 at 06:29
  • Correct. Just don't use requestForState. Just use didEnter or didEzit... – mfaani Dec 18 '17 at 21:22
  • @kidsid49 could you please check my answer? – Shamsudheen TK Dec 24 '17 at 16:33

2 Answers2

7

The issue is, you are calling the requestState using a hard-coded delay - (0.1). How do you make sure the Location Manager started monitoring your region within 0.1 seconds? You will get the exact region state of a region, only if started monitoring it.

The better method for overcoming this problem is, implement the didStartMonitoringForRegion delegate and call requestStateForRegion

locationManager.startMonitoring(for: region)

func locationManager(_ manager: CLLocationManager, didStartMonitoringFor region: CLRegion) {
    manager.requestState(for: region)
}

func locationManager(_ manager: CLLocationManager, didDetermineState state: CLRegionState, for region: CLRegion) {
   if (region is CLBeaconRegion) && state == .inside {
      locationManager(manager, didEnterRegion: region)
   }
}
Shamsudheen TK
  • 30,739
  • 9
  • 69
  • 102
0

From the CLLocationManager requestState(for:) docs:

region: The region whose state you want to know. This object must be an instance of one of the standard region subclasses provided by Map Kit. You cannot use this method to determine the state of custom regions you define yourself.

You defined the region yourself so you can't use requestState(for:) to get its state. You use that function with regions that you get back from Core Location (via the delegate methods).

If you want to know whether the device is currently inside a region, start a standard location update request (startUpdatingLocation() etc) and when you get back a recent and accurate coordinate, use the CLCircularRegion contains() function to check the coordinate.

// In the locationManager(_:didUpdateLocations:) delegate method
if myCircularRegion.contains(myCoordinate) {
    // ...
}
nevan king
  • 112,709
  • 45
  • 203
  • 241