Jak używać beginBackgroundTaskWithExpirationhandler dla już uruchomionych zadań w systemie iOS

W mojej aplikacji przesyłam zdjęcia na serwer z iPhone ' a. Podczas synchronizacji, jeśli użytkownik naciśnie przycisk home, aplikacja zostanie zamknięta.

Chcę, aby aplikacja była uruchomiona w tle do zakończenia synchronizacji.

Moje pytanie brzmi: jak Mogę dodać aktualnie uruchomione zadanie za pomocą "beginBackgroundTaskWithExpirationHandler"?

Podziel się swoimi pomysłami.
Author: elp, 2012-08-22

6 answers

Pomimo swojej nazwy, beginBackgroundTaskWithExpirationHandler: w rzeczywistości nie" rozpoczyna " zadania. Lepiej byłoby to potraktować jako " rejestr..."zamiast" zaczynać...."Po prostu mówisz systemowi, że jesteś w trakcie robienia czegoś, co chciałby zakończyć, jeśli to jest w porządku.

Kilka punktów:

  • W prawie wszystkich przypadkach, chcesz zadzwonić beginBackgroundTaskWithExpirationHandler: kiedy zaczniesz robić to, co chcesz zrobić, a następnie endBackgroundTask: Kiedy skończysz. Prawie nigdy nie dzwonisz do nich w momencie, gdy użytkownik naciska Dom przycisk (chyba, że jest to punkt, kiedy rozpoczynasz zadanie, na przykład zapisywanie czegoś na serwerze).

  • Możesz mieć tyle" zadań w tle", ile chcesz otworzyć na raz. Nic nie kosztują. Są jak liczniki. Tak długo, jak masz jeszcze jeden otwarty ("początek", który nie dotarł do jego "końca"), system uzna, że prośba o więcej czasu. Wywołanie metod "begin" I "end" jest bardzo mało kosztowne, więc użyj ich, aby uchwycić wszystko, co chcesz dodatkowy czas do końca.

  • Nie ma sposobu, aby mieć pewność, że uda Ci się zakończyć synchronizację. Te metody po prostu złożyć wniosek. System Operacyjny może nadal odrzucić to żądanie. System Operacyjny może cię zabić w każdej chwili, gdy potrzebuje dodatkowych zasobów. System operacyjny nie jest nieskończenie cierpliwy; jeśli zajmie ci to zbyt długo (zwykle około 10 minut), i tak cię zabije po wywołaniu obsługi wydechu. System Operacyjny może cię zabić, ponieważ telefon jest wyłączony. Twoja aplikacja musi być w stanie poradzić sobie z nie dotarcie do końca. System operacyjny po prostu daje Ci tę możliwość, dzięki czemu możesz poprawić wrażenia użytkownika.

 107
Author: Rob Napier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-22 14:02:17

Użyłem poniższego kodu do obsługi zadań w tle:

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

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

    [[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];

    backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}];
 17
Author: Vardhan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-08 10:33:14

Oto jak użyłem beginBackgroundTaskWithExpirationhandler, włączając w to wywołanie metody, która ma być wykonana w tle. Obejmuje to kod do rozpoczęcia nowego zadania asynchronicznego. Więc nie dokładnie to, co jest zadawane w pytaniu. Dodanie kodu poniżej, myśląc, że ktoś może szukać tego scenariusza:

- (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...");

}
 9
Author: Joe M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-26 14:05:38

Spójrz na tę stronę, Apple opisuje, jak utrzymać aplikację iOS nie zawieszoną, gdy jest w tle. Dokumentacja Apple

A oto co zaimplementowałem:

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];  
}
 6
Author: Duyen-Hoa,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-12 15:21:53

Oto mała zmiana na inne odpowiedzi, których używam, gdy aplikacja przechodzi w tło i muszę coś zrobić w głównym wątku:

- (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;
    });
}
 4
Author: BuvinJ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-09 13:46:32

Należy uruchomić zadanie po beginBackgroundTaskWithExpirationHandler lub przechwytywanie powiadomienia, gdy aplikacja zmienia stan aplikacji na tło, a następnie anulować bieżące zadanie i uruchomić ponownie z beginBackgroundTaskWithExpirationHandler.

 1
Author: tikhop,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-08-22 11:22:36