3

I'm trying to build an iPhone app that requires me to keep track of the user's location at all times using Core Location. I am using startMonitoringSignificantLocationChanges so that it updates in the background and because the accuracy is not as important as it being updated whenever there is a significant change.

Currently I make an HTTP request to a web service to update the location. This works perfectly when I am running the app - my location gets updated in the MySQL database I'm storing location data in. But when the app enters into the background - I can see the location services icon in the top right corner of the phone still running, but when I go back and look at the database, it didn't update my location at all. I tested this by taking a drive across town, one way with the app running, and one way with the app in the background.

From Apple's documentation:

If you leave this service running and your application is subsequently suspended or terminated, the service automatically wakes up your application when new location data arrives. At wake-up time, your application is put into the background and given a small amount of time to process the location data. Because your application is in the background, it should do minimal work and avoid any tasks (such as querying the network) that might prevent it from returning before the allocated time expires. If it does not, your application may be terminated.

How long exactly is this "small amount of time to process location data"? And is it just not recommended to query the network, or is it not possible to query the network in that time? Is there a better way to keep track of the location of several different users even when the app is in the background?

4

1 回答 1

4

你应该看看后台任务。

当 Apple 说small amount of time to process location data时,您不应该真正依赖在locationManager:didUpdateToLocation:fromLocation:方法返回后获得任何处理时间。假设您在单独的线程中异步运行 HTTP 请求,您可能没有足够的时间在应用程序暂停之前完成它。

UIBackgroundTasks 让你在后台请求操作系统额外的处理时间。发出 HTTP 请求可能就是这样的任务。时间限制为 10 分钟,但不能保证您有这么多时间。

在您的位置回调中,您应该为您的请求定义一个新的后台任务。如果操作系统决定它不能再给你更多的处理时间,过期处理程序块会随时触发。

- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation {
    // Start your request here
    UIBackgroundTaskIdentifier backgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
        backgroundTask = UIBackgroundTaskInvalid;
        // Cancel your request here
    }];
}

当请求完成时,您应该告诉应用程序任务已完成:

- (void)requestFinished:(id)request {
    [[UIApplication sharedApplication] endBackgroundTask:backgroundTask];
    backgroundTask = UIBackgroundTaskInvalid;
}

在此示例中,我没有考虑到您可能会在请求完成之前收到多个位置回调。如果发生这种情况,您需要在开始新的请求之前取消该请求和当前后台任务,或者为每个请求创建单独的后台任务。

另一种方法是在位置回调方法中在主线程上同步运行 HTTP 请求,但这将是一件坏事,原因有多种,例如如果用户在请求时打开应用程序会锁定界面在跑。

于 2012-07-04T13:56:14.307 回答