Fuga de límite de time de recuperación de background de iOS

He configurado la captura de background, usando el esquema del episodio 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); } 

Para el método fetchBackgroundWithSuccess:failure , estoy usando AFNetworking NSURLSessionDataTask .

Desafortunadamente, a veces me sale el error

 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 )} 

y bloquea completamente mi aplicación, desconecta a mi usuario y todos los datos del usuario se borran.

No estoy seguro de cómo solucionar esto, pero cualquier dirección sería muy apreciada.

ACTUALIZAR:

La forma en que almaceno los datos utiliza el file de archiveRootObject:toFile FileObject de archiveRootObject:toFile y archiveRootObject:toFile . Realiza un seguimiento si el usuario ha iniciado session, su user_id y otra información importante. Todo esto se almacena en caching en memory utilizando un object único de la class User .

archiveRootObject:toFile se llama durante

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

unarchiveObjectWithFile se llama según sea necesario si el singleton es nulo.

Por lo tanto, se desconecta y se limpia, significa que el singleton es nulo y unarchiveObjectWithFile no puede recuperar ningún dato.

Cada búsqueda de background tiene un límite de time, que es lo que creo que es de 30 segundos. A diferencia de una tarea de background normal que puede utilizar un manejador de caducidad para limpiar automáticamente y hacer lo que necesita hacer cuando se agota el time, las capturas de background actualmente no tienen esa capacidad. Una forma de manejar esto es quizás comenzar con un NSTimer progtwigdo para que suene como 20-25 segundos en su búsqueda de background, y hacer que ese timer llame a una function que maneja si no ha completado su tarea de background para detener lo que sea Estoy haciendo y limpiando todo para que la aplicación pueda volver a estar en segundo plano normalmente. De los documentos:

Cuando se llama a este método, su aplicación tiene hasta 30 segundos de time de reloj de panetworking para realizar la operación de descarga y llamar al bloque de manejador de finalización especificado. En la práctica, su aplicación debe llamar al bloque del manejador de finalización tan pronto como sea posible después de download los datos necesarios. Si no llama al manejador de finalización a time, su aplicación finaliza.

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

La parte audaz suena como que eso es exactamente lo que está sucediendo. De cualquier manera, debe completar lo que está intentando hacer dentro de los 30 segundos; de lo contrario, debe cancelarlo o su aplicación finalizará.

Esta pregunta es un tanto antigua, pero tal vez el siguiente código puede ayudar a algunos desarrolladores interesados ​​en un fragment de código basado en la respuesta de Mike. Como sugirió Mike, también uso un NSTimer para cancelar la captura de background cuando toma demasiado time. En mi historial de búsqueda, accedo a mi service web con AFNetworking para get algunos datos nuevos. Si la hora (elijo 25 segundos) está arriba simplemente cancelo todas mis requestes abiertas al service web en el NSOperationQueue. Aquí está mi código:

 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 } 

¡Espero que esto ayude!