Uruchamianie procesów w tle w systemie iOS za pomocą zadań

Najprostszym sposobem wykonywania w tle w systemie iOS jest podzielenie wymagań dotyczących wykonywania w tle na zadania i uruchamianie zadań w tle. Zadania są objęte ścisłym limitem czasu, a zwykle około 600 sekund (10 minut) czasu przetwarzania po przeniesieniu aplikacji do tła w systemie iOS 6 i mniej niż 10 minut w systemie iOS 7 lub nowszym.

Zadania w tle można podzielić na trzy kategorie:

  1. Zadania Sejf w tle — wywoływane w dowolnym miejscu w aplikacji, w której masz zadanie, którego nie chcesz przerywać, jeśli aplikacja wejdzie w tle.
  2. DidEnterBackground Tasks — wywoływana podczas DidEnterBackground metody cyklu życia aplikacji w celu ułatwienia czyszczenia i zapisywania stanu.
  3. Transfery w tle (iOS 7+) — specjalny typ zadania w tle używanego do wykonywania transferów sieciowych w systemie iOS 7. W przeciwieństwie do zwykłych zadań transfery w tle nie mają wstępnie określonego limitu czasu.

Bezpieczne w tle i DidEnterBackground zadania są bezpieczne do użycia zarówno w systemach iOS 6, jak i iOS 7, z niewielkimi różnicami. Przyjrzyjmy się tym dwóm typom zadań bardziej szczegółowo.

Tworzenie zadań Sejf w tle

Niektóre aplikacje zawierają zadania, które nie powinny być przerywane przez system iOS, jeśli stan zmiany aplikacji. Jednym ze sposobów ochrony tych zadań przed przerwaniem jest zarejestrowanie ich w systemie iOS jako długotrwałych zadań. Możesz użyć tego wzorca w dowolnym miejscu w aplikacji, w którym nie chcesz przerywać zadania, jeśli użytkownik umieści aplikację w tle. Doskonałym kandydatem do tego wzorca są zadania, takie jak wysyłanie informacji o rejestracji nowego użytkownika do serwera lub weryfikowanie informacji logowania.

Poniższy fragment kodu przedstawia rejestrowanie zadania do uruchomienia w tle:

nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});

//runs on main or background thread
FinishLongRunningTask(taskID);

UIApplication.SharedApplication.EndBackgroundTask(taskID);

Proces rejestracji łączy zadanie z unikatowym identyfikatorem, taskIDa następnie opakowuje je w dopasowywanie BeginBackgroundTask i EndBackgroundTask wywołania. Aby wygenerować BeginBackgroundTask identyfikator, tworzymy wywołanie metody w UIApplication obiekcie, a następnie uruchamiamy długotrwałe zadanie, zwykle w nowym wątku. Po zakończeniu zadania wywołujemy EndBackgroundTask i przekazujemy ten sam identyfikator. Jest to ważne, ponieważ system iOS zakończy działanie aplikacji, jeśli BeginBackgroundTask wywołanie nie ma pasującego EndBackgroundTaskelementu .

Ważne

Zadania bezpieczne w tle mogą być uruchamiane w wątku głównym lub w wątku w tle, w zależności od potrzeb aplikacji.

Wykonywanie zadań podczas polecenia DidEnterBackground

Oprócz zapewnienia bezpieczeństwa w tle długotrwałego zadania rejestracja może służyć do uruchamiania zadań w tle, ponieważ aplikacja jest umieszczana w tle. System iOS udostępnia metodę zdarzenia w klasie AppDelegate o nazwie DidEnterBackground , która może służyć do zapisywania stanu aplikacji, zapisywania danych użytkownika i szyfrowania poufnej zawartości przed wejściem aplikacji w tle. Aplikacja ma około pięć sekund na powrót z tej metody lub zostanie zakończona. W związku z tym zadania oczyszczania, które mogą potrwać ponad pięć sekund, mogą być wywoływane z wewnątrz DidEnterBackground metody. Te zadania muszą być wywoływane w osobnym wątku.

Proces jest prawie identyczny z procesem rejestrowania długotrwałego zadania. Poniższy fragment kodu ilustruje to w akcji:

public override void DidEnterBackground (UIApplication application) {
  nint taskID = UIApplication.SharedApplication.BeginBackgroundTask( () => {});
  new Task ( () => {
    DoWork();
    UIApplication.SharedApplication.EndBackgroundTask(taskID);
  }).Start();
}

Zaczynamy od zastąpienia DidEnterBackground metody w AppDelegatepliku , gdzie rejestrujemy zadanie za pomocą BeginBackgroundTask metody , tak jak w poprzednim przykładzie. Następnie zduplikujemy nowy wątek i wykonamy nasze długotrwałe zadanie. Należy pamiętać, że EndBackgroundTask wywołanie jest teraz wykonywane z wewnątrz długotrwałego zadania, ponieważ DidEnterBackground metoda zostanie już zwrócona.

Ważne

System iOS używa mechanizmu watchdog, aby upewnić się, że interfejs użytkownika aplikacji pozostaje dynamiczny. Aplikacja, która spędza zbyt dużo czasu, DidEnterBackground przestanie odpowiadać w interfejsie użytkownika. Uruchamianie zadań do uruchamiania w tle pozwala DidEnterBackground na powrót w odpowiednim czasie, zachowanie reakcji interfejsu użytkownika i zapobieganie zabijaniu aplikacji przez watchdog.

Obsługa limitów czasu zadania w tle

System iOS nakłada ścisłe limity czasu działania zadania w tle, a jeśli EndBackgroundTask wywołanie nie zostanie wykonane w wyznaczonym czasie, aplikacja zostanie zakończona. Dzięki śledzeniu pozostałego czasu w tle i używaniu procedur obsługi wygasania w razie potrzeby możemy uniknąć zakończenia aplikacji przez system iOS.

Uzyskiwanie dostępu do pozostałego czasu w tle

Jeśli aplikacja z zarejestrowanymi zadaniami zostanie przeniesiona w tle, zarejestrowane zadania zostaną uruchomione około 600 sekund. Możemy sprawdzić, ile czasu zadanie musi wykonać przy użyciu właściwości statycznej BackgroundTimeRemainingUIApplication klasy. Poniższy kod da nam czas (w sekundach), że nasze zadanie w tle pozostało:

double timeRemaining = UIApplication.SharedApplication.BackgroundTimeRemaining;

Unikanie kończenia działania aplikacji przy użyciu procedur obsługi wygasania

Oprócz udzielenia dostępu do BackgroundTimeRemaining właściwości system iOS zapewnia bezproblemowy sposób obsługi wygaśnięcia czasu w tle za pośrednictwem programu obsługi wygasania wygasania. Jest to opcjonalny blok kodu, który zostanie wykonany, gdy czas przydzielony do zadania wkrótce wygaśnie. Kod w wywołaniach programu obsługi wygasania EndBackgroundTask i przekazuje identyfikator zadania, który wskazuje, że aplikacja działa dobrze i uniemożliwia systemowi iOS kończenie działania aplikacji, nawet jeśli zadanie kończy się z upływem czasu. EndBackgroundTask należy wywołać program obsługi wygasania, a także w normalnym przebiegu wykonywania.

Procedura obsługi wygasania jest wyrażana jako funkcja anonimowa przy użyciu wyrażenia lambda, jak pokazano poniżej:

Task.Factory.StartNew( () => {

    //expirationHandler only called if background time allowed exceeded
    var taskId = UIApplication.SharedApplication.BeginBackgroundTask(() => {
        Console.WriteLine("Exhausted time");
        UIApplication.SharedApplication.EndBackgroundTask(taskId); 
    });
    while(myFlag == true)
    {
        Console.WriteLine(UIApplication.SharedApplication.BackgroundTimeRemaining);
        myFlag = SomeCalculationNeedsMoreTime();
    }
    //Only called if loop terminated due to myFlag and not expiration of time
    UIApplication.SharedApplication.EndBackgroundTask(taskId);
});

Chociaż programy obsługi wygasania nie są wymagane do uruchomienia kodu, należy zawsze używać programu obsługi wygasania z zadaniem w tle.

Zadania w tle w systemie iOS 7 lub nowszym

Największą zmianą w systemie iOS 7 w odniesieniu do zadań w tle nie jest sposób implementowania zadań, ale po uruchomieniu.

Przypomnij sobie, że przed systemem iOS 7 zadanie uruchomione w tle miało 600 sekund do ukończenia. Jednym z powodów tego limitu jest to, że zadanie uruchomione w tle spowoduje, że urządzenie obudziłoby się przez czas trwania zadania:

Graph of the task keeping the app awake pre-iOS 7

Przetwarzanie w tle systemu iOS 7 jest zoptymalizowane pod kątem dłuższego czasu pracy baterii. W systemie iOS 7 tło staje się oportunistyczne: zamiast utrzymywać stan uśpienia urządzenia, podzadania, gdy urządzenie przechodzi w stan uśpienia, a zamiast tego wykonywać przetwarzanie we fragmentach, gdy urządzenie budzi się w celu obsługi połączeń telefonicznych, powiadomień, przychodzących wiadomości e-mail i innych typowych przerw. Poniższy diagram zawiera szczegółowe informacje o tym, jak można podzielić zadanie:

Graph of the task being broken into chunks post-iOS 7

Ponieważ czas wykonywania zadania nie jest już ciągły, zadania wykonujące transfery sieciowe muszą być obsługiwane inaczej w systemie iOS 7. Deweloperzy są zachęcani do korzystania z interfejsu NSURlSession API do obsługi transferów sieciowych. Następna sekcja zawiera omówienie transferów w tle.

Transfery w tle

Szkielet transferów w tle w systemie iOS 7 to nowy NSURLSession interfejs API. NSURLSession umożliwia tworzenie zadań w celu:

  1. Transferowanie zawartości za pośrednictwem przerw w działaniu sieci i urządzeń.
  2. Przekazywanie i pobieranie dużych plików ( usługa transferu w tle).

Przyjrzyjmy się bliżej temu, jak to działa.

NSURLSession API

NSURLSession to zaawansowany interfejs API do przesyłania zawartości za pośrednictwem sieci. Udostępnia zestaw narzędzi do obsługi transferu danych przez przerwy w działaniu sieci i zmian w stanach aplikacji.

Interfejs NSURLSession API tworzy jedną lub kilka sesji, co z kolei powoduje zduplikowania zadań do bloków transferowych powiązanych danych w całej sieci. Zadania są uruchamiane asynchronicznie, aby szybko i niezawodnie przesyłać dane. Ponieważ NSURLSession jest asynchroniczna, każda sesja wymaga bloku obsługi ukończenia, aby poinformować system i aplikację o zakończeniu transferu.

Aby wykonać transfer sieciowy, który jest prawidłowy zarówno w systemie iOS 7, jak i po iOS 7, sprawdź, czy element NSURLSession jest dostępny do przesyłania w kolejce, i użyj zwykłego zadania w tle do wykonania transferu, jeśli nie jest:

if ([NSURLSession class]) {
  // Create a background session and enqueue transfers
}
else {
  // Start a background task and transfer directly
  // Do NOT make calls to update the UI here!
}

Ważne

Unikaj wykonywania wywołań w celu zaktualizowania interfejsu użytkownika z poziomu tła w kodzie zgodnym z systemem iOS 6, ponieważ system iOS 6 nie obsługuje aktualizacji interfejsu użytkownika w tle i zakończy działanie aplikacji.

Interfejs NSURLSession API zawiera bogaty zestaw funkcji do obsługi uwierzytelniania, zarządzania nieudanymi transferami i raportowania po stronie klienta — ale nie po stronie serwera — błędów. Ułatwia ona łączenie przerw w czasie wykonywania zadań wprowadzonych w systemie iOS 7, a także zapewnia obsługę szybkiego i niezawodnego przesyłania dużych plików. W następnej sekcji przedstawiono tę drugą funkcję.

Usługa transferu w tle

Przed systemem iOS 7 przekazywanie lub pobieranie plików w tle było zawodne. Zadania w tle mają ograniczony czas do uruchomienia, ale czas potrzebny na transfer pliku różni się w zależności od sieci i rozmiaru pliku. W systemie iOS 7 możemy użyć elementu NSURLSession , aby pomyślnie przekazać i pobrać duże pliki. Określony NSURLSession typ sesji, który obsługuje transfery sieciowe dużych plików w tle, jest znany jako usługa transferu w tle.

Transfery inicjowane przy użyciu usługi transferu w tle są zarządzane przez system operacyjny i zapewniają interfejsy API do obsługi uwierzytelniania i błędów. Ponieważ transfery nie są powiązane przez dowolny limit czasu, mogą służyć do przekazywania lub pobierania dużych plików, automatycznej aktualizacji zawartości w tle i nie tylko. Aby uzyskać szczegółowe informacje na temat implementowania usługi, zapoznaj się z przewodnikiem transferu w tle.

Usługa transferu w tle jest często sparowana z funkcjami pobierania w tle lub powiadomień zdalnych, aby ułatwić aplikacjom odświeżanie zawartości w tle. W dwóch następnych sekcjach przedstawimy koncepcję rejestrowania całych aplikacji do uruchamiania w tle zarówno w systemach iOS 6, jak i iOS 7.