写于2013-11-26
从 iOS 7 开始,程序就可以在退到后台时干一些事情了,包括获取用户位置、获取网络数据等,本文将介绍如何在后台获取网络数据。
实现
要使用后台获取网络数据的功能只需要在 Xcode5 中的项目设置切到 Capabilities 勾选 Background Modes 中的 Background fetch 即可,如图
或者直接在 info.plist 文件中添加 key UIBackgroundModes
并选择 background fetch 。
首先设置后台获取的时间间隔:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
UIApplicationBackgroundFetchIntervalMinimum
表示最小的时间间隔,而 UIApplicationBackgroundFetchIntervalNever
就表示停止后台获取了。你也可以设置你自己想要的时间间隔,比如天气类的软件就可以设置成1小时即3600秒。要说明的是,这个时间间隔并不是绝对的,是否调用获取函数完全是系统说了算,你设置的时间只是最小时间,比如你设置成1小时并不是每小时都会调用获取函数,当系统高兴时每次调用的时间间隔不会小于1小时,如果系统不高兴了可能1天都不会调用一次。
那么在哪里获取网络数据呢?你需要在 app delegate 文件中添加如下代码:
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult result))completionHandler {
__block UIBackgroundFetchResult result = UIBackgroundFetchResultFailed;
[[AFHTTPSessionManager manager] GET:url
parameters:parameters
success:^(NSURLSessionDataTask *task, id responseObject) {
if (responseObject)
result = UIBackgroundFetchResultNewData;
else
result = UIBackgroundFetchResultNoData;
completionHandler(result);
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
result = UIBackgroundFetchResultFailed;
completionHandler(result);
}];
}
上面的代码是使用 AFNetworking
在后台获取网络数据的基本逻辑。其中需要注意的是 completionHandler
函数,不管获取数据成功还是失败,一定要在最后调用该函数并传入相应的 UIBackgroundFetchResult
。
为什么一定要调用 completionHandler
呢?首先,系统根据 result
的值来判断你的程序在后台程序里的优先级和后台调用行为,如果你不调用该函数,在一段时间之后系统将不再激活你的程序去后台获取了。其次,系统会在调用 completionHandler
时截取你的应用更新数据后的新UI截图,并用于后台切换的示意图(即双击home键实现的应用图片)
测试
运行程序后,如图点击 Debug 菜单中的 Simulate Background Fetch 即可。
另一种方法稍微复杂一点,修改 Scheme 或新建一个 Scheme ,在 Scheme 设置的 Options 标签下选中 Background Fetch ,如图:
由于后台获取的不确定性,想实机测试的话比较困难,可以将获取间隔设置成 UIApplicationBackgroundFetchIntervalMinimum
,同时关掉系统所有其他后台程序(双击home键并滑出),然后锁屏并等待5分钟以上,在解锁机器后调用后台获取的概率比较大。
注意
- 后台获取并不是无限制的,系统在激活你的应用之后会给大概30秒的时间用于处理网络数据,所以应该尽量减少数据获取量并避免更新UI,更好的方式是在后台获取少量数据并存储然后在下次进入应用时再更新必要的UI变化
- 后台调用具有不确定性,所以不要用于需要准确性的功能,比如定时提醒
- 在不需要后台获取时将获取间隔设为
UIApplicationBackgroundFetchIntervalNever
,避免不必要的消耗 - 不要一味的将获取间隔设为最小值,根据你的应用的需求来设置,比如只会每天变化的数据就应该设置成24*3600秒