2012-08-22 18 views
37

Nella mia app, sto caricando le immagini sul server da iPhone. Durante la sincronizzazione se l'utente preme il tasto home, l'app si chiuderà.Come utilizzare beginBackgroundTaskWithExpirationHandler per un'attività già in esecuzione in iOS

Voglio che l'app sia in esecuzione in background fino al termine della sincronizzazione.

La mia domanda è: Come posso aggiungere un'attività attualmente in esecuzione con "beginBackgroundTaskWithExpirationHandler"?

Si prega di condividere le vostre idee.

risposta

13

ho usato qui di seguito il codice per lo sfondo gestore compito:

__block UIBackgroundTaskIdentifier backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 

    NSLog(@"Background Time:%f",[[UIApplication sharedApplication] backgroundTimeRemaining]); 

    [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier]; 

    backgroundTaskIdentifier = UIBackgroundTaskInvalid; 
}]; 
+1

cosa fa il metodo [self endBackgroundTask]? Cos'è il sé? – ozgur

+0

@ozgurv: codice aggiornato. grazie – Vardhan

1

È consigliabile eseguire l'attività dopo lo beginBackgroundTaskWithExpirationHandler o acquisire la notifica quando l'applicazione modifica lo stato dell'app in background, quindi annulla l'attività corrente ed esegui nuovamente con beginBackgroundTaskWithExpirationHandler.

95

Nonostante il nome, beginBackgroundTaskWithExpirationHandler: in realtà non "inizia" un'attività. Potrebbe essere meglio pensato come "registrati ..." piuttosto che "begin ...." Stai solo dicendo al sistema che sei nel mezzo di fare qualcosa che vorrebbe completare se è ok.

diversi punti:

  • In quasi tutti i casi, si desidera chiamare beginBackgroundTaskWithExpirationHandler: quando si inizia a fare la cosa che vuoi fare, e poi endBackgroundTask: quando il gioco è fatto. Non li chiamate quasi mai al punto in cui l'utente preme il pulsante Home (a meno che non sia il punto in cui si avvia l'attività, ad esempio il salvataggio di qualcosa sul server).

  • È possibile avere tante "attività in background" che si desidera aprire alla volta. Costano niente. Sono come i conti di mantenimento. Finché ne hai ancora uno aperto (un "inizio" che non arriva alla sua "fine"), allora il sistema considererà una richiesta per più tempo. C'è un costo molto basso per chiamare i metodi "inizio" e "fine", quindi usali per raggruppare tutto ciò che vuoi più tempo per finire.

  • Non c'è modo di essere certi di finire la sincronizzazione. Questi metodi fanno solo una richiesta. Il sistema operativo può ancora negare tale richiesta. Il sistema operativo potrebbe comunque ucciderti ogni volta che sono necessarie risorse extra. Il sistema operativo non è infinitamente paziente; se impieghi troppo tempo (circa 10 minuti di solito), ti ucciderà comunque dopo aver chiamato il tuo expiration handler. Il sistema operativo potrebbe ucciderti perché il telefono è spento. La tua app deve essere in grado di gestire non arrivare al traguardo. Il sistema operativo ti offre questa capacità per migliorare l'esperienza dell'utente.

+16

La tua risposta è completamente fantastica, grazie. Solo un aggiornamento: da iOS 7 hai solo 3 minuti per le attività in background, non più 10. –

+0

è consigliabile utilizzare beginBackgroundTaskWithExpirationHandler con scansione di dispositivi bluetooth su sfondo app? – theFool

+0

La scansione in background Bluetooth è generalmente meglio eseguita registrando con la modalità background bluetooth-central. La scansione generalmente non rientra nel "solo bisogno di un po 'più di tempo per finire questo" campo. –

8

Ecco come ho usato beginBackgroundTaskWithExpirationHandler, tra cui la chiamata al metodo deve essere fatto in background. Questo include il codice per l'avvio della nuova attività asincrona. Quindi non esattamente quello che viene chiesto nella domanda. L'aggiunta di codice qui sotto, pensando che qualcuno potrebbe essere alla ricerca di questo scenario:

- (void)didReceiveObjList:(CFDataRef)message 
{ 
    // Received Object List. Processing the list can take a few seconds. 
    // So doing it in separate thread with expiration handler to ensure it gets some time to do  the task even if the app goes to background. 

    UIApplication *application = [UIApplication sharedApplication]; 
    __block UIBackgroundTaskIdentifier bgTask = [application beginBackgroundTaskWithExpirationHandler:^{ 
    [application endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid; 
}]; 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
     [self processObjList:message]; 

    [application endBackgroundTask:bgTask]; 
    bgTask = UIBackgroundTaskInvalid; 
    }); 

    NSLog(@"Main Thread proceeding..."); 

} 
5

Date un'occhiata a questa pagina, Apple descrive come mantenere l'applicazione iOS non sospesa mentre è in background. Apple Documentation

E qui è quello che ho implementato:

UIBackgroundTaskIdentifier bgTask; 

- (void)applicationDidEnterBackground:(UIApplication *)application 
{ 
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 
    NSLog(@"=== DID ENTER BACKGROUND ==="); 
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     NSLog(@"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'"); 
     // [self askToRunMoreBackgroundTask]; This code seems to be unnecessary. I'll verify it. 
    }]; 

    if (bgTask == UIBackgroundTaskInvalid) { 
     NSLog(@"This application does not support background mode"); 
    } else { 
     //if application supports background mode, we'll see this log. 
     NSLog(@"Application will continue to run in background"); 
    } 
} 

/* 

- (void)askToRunMoreBackgroundTask 
{ 
    [[UIApplication sharedApplication] endBackgroundTask:bgTask]; 
    NSLog(@"restart background long-running task"); 
    bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ 
     NSLog(@"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'"); 
     [self askToRunMoreBackgroundTask]; 
    }]; 

} 

*/ 

- (void)applicationWillEnterForeground:(UIApplication *)application 
{ 
    NSLog(@"=== GOING BACK FROM IDLE MODE ==="); 
    //it’s important to stop background task when we do not need it anymore 
    [[UIApplication sharedApplication] endBackgroundTask:UIBackgroundTaskInvalid]; 
} 
3

Ecco una leggera variazione sulle altre risposte che sto usando quando l'applicazione sta per background e ho bisogno di fare qualcosa il thread principale:

- (void)applicationWillResignActive:(UIApplication *)application 
{ 
    UIApplication *app = [UIApplication sharedApplication]; 

    // Register auto expiring background task 
    __block UIBackgroundTaskIdentifier bgTaskId = 
     [app beginBackgroundTaskWithExpirationHandler:^{ 
     [app endBackgroundTask:bgTaskId]; 
     bgTaskId = UIBackgroundTaskInvalid; 
    }]; 

    // Execute background task on the main thread 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     // ------------------ 
     // DO SOMETHING INVOLVING THE WEBVIEW - WHICH MUST OCCUR ON THE MAIN THREAD! 
     // ------------------ 
     [app endBackgroundTask:bgTaskId]; 
     bgTaskId = UIBackgroundTaskInvalid; 
    }); 
} 
Problemi correlati