iOS背景获取时间限制崩溃

我已经设置了背景获取,使用NSScreencast第92集的轮廓。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { ... [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; ... } - (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { if ([[MyAppAPIClient manager] reachable] && [[Session manager] userSignedIn]) { [[[Session manager] user] fetchBackgroundWithSuccess:^(NSURLSessionDataTask *task, NSDictionary *responseObject) { completionHandler(UIBackgroundFetchResultNewData); } failure:^(NSURLSessionDataTask *task, NSError *error) { completionHandler(UIBackgroundFetchResultFailed); }]; } else completionHandler(UIBackgroundFetchResultNoData); } 

对于fetchBackgroundWithSuccess:failure方法,我正在使用AFNetworking NSURLSessionDataTask

不幸的是,有时我得到错误

 MyApp[3344] has active assertions beyond permitted time: {( <BKProcessAssertion: 0x178279c00> identifier: Background Content Fetching (1596) process: MyApp[3344] permittedBackgroundDuration: 30.000000 reason: backgroundContentFetching owner pid:16 preventSuspend preventThrottleDownUI preventIdleSleep preventSuspendOnSleep )} 

它完全崩溃我的应用程序,注销我的用户,所有用户的数据被擦干净。

不知道如何解决这个问题,但任何方向将不胜感激。

更新:

我存储数据的方式是使用NSKeyedArchiver的archiveRootObject:toFileunarchiveObjectWithFile 。 它跟踪用户是否login,他们的user_id和其他重要信息。 这全部使用类User的单例对象caching在内存中。

archiveRootObject:toFile在调用期间

  1. applicationWillResignActive
  2. applicationDidEnterBackground
  3. applicationWillTerminate
  4. applicationDidReceiveMemoryWarning

如果单例为零,则根据需要调用unarchiveObjectWithFile

所以注销和擦干净意味着单身是零和unarchiveObjectWithFile无法检索任何数据。

每个背景获取有一个时间限制,这是我相信30秒。 与正常的后台任务不同,后台任务可以利用过期处理程序自动清理并在耗尽时间后执行所需的操作,但后台提取目前不具备该function。 有一种方法可以处理这个问题,也许开始一个NSTimer,计划在你的后台抓取时间为20-25秒,然后让这个计时器调用一个函数来处理,如果你还没有完成你的后台任务,正在做和清理一切,所以应用程序可以回到正常的背景。 从文档:

当这个方法被调用时,你的应用程序有最多30秒的挂钟时间来执行下载操作并调用指定的完成处理程序块。 在实践中,您的应用程序应该在下载所需数据后尽快调用完成处理程序块。 如果您不及时调用完成处理程序,则您的应用程序将被终止。

https://developer.apple.com/library/ios/documentation/uikit/reference/uiapplicationdelegate_protocol/Reference/Reference.html#//apple_ref/occ/intfm/UIApplicationDelegate/application:performFetchWithCompletionHandler

大胆的部分听起来就是这样发生的事情。 无论哪种方式,您都需要在30秒内完成您想要完成的任务,否则您需要取消它,否则您的应用程序将被终止。

这个问题是古老的,但也许下面的代码可以帮助一些开发人员对Mike的答案感兴趣的代码片段。 正如Mike所build议的,当需要太多时间时,我也使用NSTimer来取消后台获取。 在我的后台获取我访问我的Web服务与AFNetworking获取一些新的数据。 如果(我select了25秒)的时间到了,我只需取消所有打开的请求到NSOperationQueue中的web服务。 这里是我的代码:

 func application(application: UIApplication, performFetchWithCompletionHandler completionHandler: (UIBackgroundFetchResult) -> Void) { // This Handler accesses my webservice using AFNetworking and creates NSOperationQueue to enqueue the requests backgroundSearchHandler = BackgroundFetchSearchHandler() let cancelTimer = NSTimer.scheduledTimerWithTimeInterval(25, target: self, selector: "cancelBackgroundFetch", userInfo: nil, repeats: false) backgroundSearchHandler!.findNewResultsForSavedSearches { (completed, newResultCount) -> Void in // This block is also called when the timer is over and the requests were cancelled // Stop the timer cancelTimer.invalidate() if !completed { completionHandler(.Failed) return } if newResultCount <= 0 { completionHandler(.NoData) return } completionHandler(.NewData) } } func cancelBackgroundFetch() { backgroundSearchHandler?.cancel() // This is calling cancelAllOperations() on the NSOperationQueue in my background search handler } 

希望这可以帮助!