3

I have an app which does periodic location updates to map the users path.

I am using deferred updates.

if (CLLocationManager.deferredLocationUpdatesAvailable() == true && _isDeferingUpdates == false)
        {
            print("Doing refresh")
            _isDeferingUpdates = true
            _locationManager.allowDeferredLocationUpdatesUntilTraveled(C_GPS.ACTIVITY_UPDATE_DISTANCE, timeout: C_GPS.ACTIVITY_UPDATE_TIME)
        } else
        {
            print("Could not refresh")
            // iPhone 4S does not have deferring so must keep it always on
            _locationManager.startUpdatingLocation()
        }

When the app is open I get the "doing refresh" call every second.

My setup:

Have the 2 keys on my pList NSLocationWhenInUseUsageDescription && NSLocationAlwaysUsageDescription

Have background modes turned on, for Remote Notifcations and Location Updates.

Have Maps setup to use Bike and Pedestrian.

Have all the permissions on my phone set to yes.

Do you know any other reason why my deferred update is failing when my app goes to the background?

Its never working and apples documentation is less than helpful

DeferredFailed The location manager did not enter deferred mode for an unknown reason. This error can occur if GPS is unavailable, not active, or is temporarily interrupted. If you get this error on a device that has GPS hardware, the solution is to try again.

Here is my error handler:

func locationManager(manager: CLLocationManager, didFinishDeferredUpdatesWithError error: NSError?)
{
    print("FINISHED BACKGROUND UPDATE with error \(error)")
    if (error != nil)
    {
        print("ERROR IS VALID as CLError")

        if (error!.code == CLError.LocationUnknown.rawValue)
        {
            print("Error: Location Unknown")
        } else if (error!.code == CLError.DeferredAccuracyTooLow.rawValue)
        {
            print("Error: Accuracy too low")
        } else if (error!.code == CLError.DeferredFailed.rawValue)
        {
            print("Error: Deferring Failed")
        } else if (error!.code == CLError.Denied.rawValue)
        {
            print("Error: Denied")
        } else
        {
            print("Error not handled")
        }

    }
    _isDeferingUpdates = false
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
Aggressor
  • 13,323
  • 24
  • 103
  • 182
  • I found this looking for iOS 10 http://stackoverflow.com/questions/39498899/deferredlocationupdatesavailable-returns-no-in-ios-10 – Mc Gz Mar 25 '17 at 00:16
  • I found this looking for iOS 10 http://stackoverflow.com/questions/39498899/deferredlocationupdatesavailable-returns-no-in-ios-10 – Mc Gz Mar 25 '17 at 00:20

3 Answers3

3

iOS 9.2, Xcode 7.2, ARC enabled

The problem is most likely associated with the distance and time interval you have chosen for your deferral. Try to take advantage of CLLocationDistanceMaxand CLTimeIntervalMax to troubleshoot the function call. For example, set the distance to CLLocationDistanceMax and then vary the time interval, then try vice versa.

But there are other things I see that you might want to change...

  1. Get rid of CLLocationManager.deferredLocationUpdatesAvailable() == true condition in the if statements to allow deferred location updates.
  2. Deferred updates were available iOS6.0+, most iPhone 4S can be updated to iOS7.2.1 depending on the hardware. You do not need to separately call _locationManager.startUpdatingLocation().
  3. Make sure that if you are testing in iOS9.0+ that you have the allowsBackgroundLocationUpdates set for the location manager.
  4. Make sure that the initial _locationManager.startUpdatingLocation() is made in the - (void)applicationWillResignActive:(UIApplication *)application method equivalent in Swift and NOT in the - (void)applicationDidEnterBackground:(UIApplication *)application method.
  5. Make sure that you are calling _locationManager.allowDeferredLocationUpdatesUntilTraveled(C_GPS.ACTIVITY_UPDATE_DISTANCE, timeout: C_GPS.ACTIVITY_UPDATE_TIME) in the equivalent of the - (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations method for Swift.

Also, note that you are printing the error before you check if the error exists, this might lead to some incorrect error reporting.

Hope this helps and I am not too late! Cheers.

P.S. If this doesn't work, then please post more of your code, i.e. where you are calling these functions in relation to the app. delegate *.m file.

serge-k
  • 3,394
  • 2
  • 24
  • 55
  • This is not too late at all. I am just getting back to this problem next week. Thank you for this reply it will help a lot. I will dig in on this and get back with answers when I find it. Thank you! – Aggressor Jan 08 '16 at 17:11
  • @Aggressor, sounds good! I hope that it goes better for you. I just finished wrapping up my location deferral scheme for one of my apps., waiting on App Store for review. Let me know if I can be of further assistance. – serge-k Jan 09 '16 at 01:12
1

The error was misleading. The issue is the 4S does not support background updates. As such, for the 4S I was manually refereshing the updates like so:

private func refreshUpdateDeferral()
{
    if (CLLocationManager.deferredLocationUpdatesAvailable() == false && _isDeferingUpdates == false)
    {
        print("Doing deferred referral refresh")

        _isDeferingUpdates = true
        _locationManager.allowDeferredLocationUpdatesUntilTraveled(C_GPS.ACTIVITY_UPDATE_DISTANCE, timeout: C_GPS.ACTIVITY_UPDATE_TIME)
    }
}

The problem was I had CLLocationManager.deferredLocationUpdatesAvailable() == true which mean I was deferring updates when deferring was already allowed. This seems to cause the error above.

So if you get this error, check that you aren't allowDeferredLocationUpdatesUntilTraveled while deferredUpdates is already active!

Aggressor
  • 13,323
  • 24
  • 103
  • 182
  • good find! I'll have to check my code to see if I missed that for any of my apps. Glad you were able to find the error. Yeah I it is always a balance between by which deferral method you choose, and each strategy seems to conflict with each other. – serge-k Jan 27 '16 at 22:49
0

You can run into trouble with deferred updates if your accuracy and distance filter are not set correctly. Assuming your device supports deferred updates (CLLocationManager.deferredLocationUpdatesAvailable), you must set your location manager to the following first:

desiredAccuracy = kCLLocationAccuracyBest
distanceFilter = kCLDistanceFilterNone

Then you can start the location manager and allow deferred updates.

pbc
  • 515
  • 4
  • 11