Understanding the iOS 13 Scene Delegate

Published by donnywals on October 28, 2019October 28, 2019

Gdy tworzysz nowy projekt w Xcode 11, możesz zauważyć coś, czego wcześniej nie widziałeś. Zamiast tworzyć tylko plik AppDelegate.swift, plik ViewController.swift, storyboard i kilka innych plików, Xcode tworzy teraz dla ciebie nowy plik; plik SceneDelegate.swift. Jeśli nigdy wcześniej nie widziałeś tego pliku, może to być dość mylące, aby zrozumieć, co to jest i jak masz używać tego nowego delegata sceny w swojej aplikacji.

Pod koniec tego tygodniowego wpisu na blogu będziesz wiedział:

  • Do czego służy delegat sceny.
  • Jak możesz skutecznie zaimplementować swojego delegata sceny.
  • Dlaczego delegat sceny jest ważną częścią systemu iOS 13.

Zacznijmy od razu, dobrze?

Poznanie nowego szablonu projektu Xcode

Gdy tworzysz nowy projekt Xcode, masz możliwość wyboru, czy chcesz używać SwiftUI czy Storyboards. Niezależnie od tego, co wybierzesz, Xcode wygeneruje nowy rodzaj szablonu projektu, na którym będziesz mógł budować. Przyjrzymy się bliżej plikom SceneDelegate.swift i AppDelegate.swift w następnej sekcji, ważne jest teraz, abyś zrozumiał, że Xcode stworzył te pliki dla Ciebie.

Oprócz tych dwóch plików delegatów, Xcode robi coś nieco bardziej subtelnego. Przyjrzyj się uważnie swojemu plikowi Info.plist. Powinieneś zobaczyć nowy klucz o nazwie Application Scene Manifest z zawartością podobną do poniższego obrazu:

Zrzut ekranu manifestu sceny pliku Info.plist

Zrzut ekranu manifestu sceny pliku Info.plist

Ten manifest sceny określa nazwę i klasę delegata dla twojej sceny. Zauważ, że te właściwości należą do tablicy (Application Session Role), co sugeruje, że możesz mieć wiele konfiguracji w swoim Info.plist. Znacznie ważniejszym kluczem, który być może już zauważyłeś na powyższym zrzucie ekranu, jest Enable Multiple Windows. Ta właściwość jest domyślnie ustawiona na NO. Ustawienie tej właściwości na YES pozwoli użytkownikom na otwieranie wielu okien Twojej aplikacji na iPadOS (lub nawet na macOS). Możliwość uruchamiania wielu okien aplikacji iOS obok siebie to ogromna różnica w stosunku do środowiska pojedynczego okna, z którym pracowaliśmy do tej pory, a możliwość posiadania wielu okien jest całym powodem, dla którego cykl życia naszej aplikacji jest teraz utrzymywany w dwóch miejscach, a nie w jednym.

Przyjrzyjmy się bliżej AppDelegate i SceneDelegate, aby lepiej zrozumieć, w jaki sposób te dwie delegatki współpracują ze sobą, aby umożliwić obsługę wielu okien.

Zrozumienie ról AppDelegate i SceneDelegate

Jeśli zbudowałeś aplikacje przed iOS 13, prawdopodobnie znasz swój AppDelegate jako jedno miejsce, które robi całkiem sporo wszystkiego związanego z uruchomieniem aplikacji, pierwszym planem, tłem i jeszcze trochę. W systemie iOS 13 firma Apple przeniosła niektóre z obowiązków AppDelegate do SceneDelegate. Przyjrzyjmy się pokrótce każdemu z tych dwóch plików.

ObowiązkiAppDelegate

The AppDelegate jest nadal głównym punktem wejścia dla aplikacji w iOS 13. Apple wywołuje metody AppDelegate dla kilku zdarzeń cyklu życia na poziomie aplikacji. W domyślnym szablonie Apple znajdziesz trzy metody, które Apple uważa za ważne, abyś ich używał:

  • func application(_:didFinishLaunchingWithOptions:) -> Bool
  • func application(_:configurationForConnecting:options:) -> UISceneConfiguration
  • func application(_:didDiscardSceneSessions:)

Te metody mają w sobie pewien komentarz, który faktycznie opisuje to, co robią na tyle szczegółowo, aby zrozumieć, co robią. Ale i tak szybko je przejrzyjmy.

Gdy Twoja aplikacja jest właśnie uruchamiana, wywoływana jest metoda func application(_:didFinishLaunchingWithOptions:) -> Bool. Ta metoda jest używana do wykonywania konfiguracji aplikacji. W systemie iOS 12 lub wcześniej, mogłeś użyć tej metody do utworzenia i skonfigurowania obiektu UIWindow i przypisać instancję UIViewController do okna, aby się pojawiło.

Jeśli twoja aplikacja używa scen, twój AppDelegate nie jest już odpowiedzialny za robienie tego. Ponieważ twoja aplikacja może mieć teraz wiele aktywnych okien lub UISceneSessions, nie ma sensu zarządzać obiektem pojedynczego okna w AppDelegate.

Metoda func application(_:configurationForConnecting:options:) -> UISceneConfiguration jest wywoływana za każdym razem, gdy twoja aplikacja ma dostarczyć nową scenę lub okno dla iOS do wyświetlenia. Zauważ, że ta metoda nie jest wywoływana, gdy twoja aplikacja uruchamia się początkowo, jest ona wywoływana tylko w celu uzyskania i utworzenia nowych scen. Przyjrzymy się głębiej tworzeniu i zarządzaniu wieloma scenami w późniejszym wpisie na blogu.

Ostatnią metodą w szablonie AppDelegate jest func application(_:didDiscardSceneSessions:). Ta metoda jest wywoływana za każdym razem, gdy użytkownik odrzuca scenę, na przykład przez przesunięcie jej w oknie wielozadaniowości lub jeśli zrobisz to programowo. Jeśli twoja aplikacja nie jest uruchomiona, gdy użytkownik to robi, ta metoda zostanie wywołana dla każdej odrzuconej sceny wkrótce po wywołaniu func application(_:didFinishLaunchingWithOptions:) -> Bool.

Oprócz tych domyślnych metod, twój AppDelegate może być nadal używany do otwierania adresów URL, wychwytywania ostrzeżeń o pamięci, wykrywania, kiedy twoja aplikacja zostanie zakończona, czy zegar urządzenia zmienił się znacząco, wykrywania, kiedy użytkownik zarejestrował się do zdalnych powiadomień i więcej.

Wskazówka:
Należy pamiętać, że jeśli obecnie używasz AppDelegate do zarządzania wyglądem paska stanu aplikacji, być może będziesz musiał dokonać pewnych zmian w systemie iOS 13. Kilka metod związanych z paskiem stanu zostało zdeprecjonowanych w iOS 13.

Teraz, gdy mamy lepszy obraz tego, jakie są nowe obowiązki twojego AppDelegate, spójrzmy na nowe SceneDelegate.

Obowiązki SceneDelegate

Jeśli uważasz, że AppDelegate jest obiektem odpowiedzialnym za cykl życia twojej aplikacji, SceneDelegate jest odpowiedzialny za to, co jest wyświetlane na ekranie; sceny lub okna. Zanim będziemy kontynuować, ustalmy pewne słownictwo związane ze scenami, ponieważ nie każdy termin oznacza to, co może się wydawać, że oznacza.

Gdy masz do czynienia ze scenami, to, co wygląda jak okno dla użytkownika, jest w rzeczywistości nazywane UIScene, które jest zarządzane przez UISceneSession. Więc kiedy odnosimy się do okien, tak naprawdę odnosimy się do obiektów UISceneSession. Postaram się trzymać się tej terminologii tak bardzo, jak to możliwe w trakcie tego wpisu na blogu.

Teraz, gdy jesteśmy na tej samej stronie, spójrzmy na plik SceneDelegate.swift, który Xcode utworzył podczas tworzenia naszego projektu.

Domyślnie w pliku SceneDelegate.swift znajduje się kilka metod:

  • scene(_:willConnectTo:options:)
  • sceneDidDisconnect(_:)
  • sceneDidBecomeActive(_:)
  • sceneWillResignActive(_:)
  • sceneWillEnterForeground(_:)
  • sceneDidEnterBackground(_:)

Te metody powinny wyglądać bardzo znajomo, jeśli jesteś zaznajomiony z AppDelegate, które istniały przed iOS 13. Spójrzmy najpierw na scene(_:willConnectTo:options:), ta metoda prawdopodobnie wygląda najmniej znajomo i jest pierwszą metodą wywoływaną w cyklu życia UISceneSession.

Domyślna implementacja scene(_:willConnectTo:options:) tworzy twój początkowy widok zawartości (ContentView, jeśli używasz SwiftUI), tworzy nowy UIWindow, ustawia rootViewController okna i czyni to okno oknem kluczowym. Możesz myśleć o tym oknie jako o oknie, które widzi twój użytkownik. Niestety, tak nie jest. Okna istnieją od czasów przed iOS 13 i reprezentują rzutnię, w której działa Twoja aplikacja. Tak więc, UISceneSession kontroluje widoczne okno, które widzi użytkownik, UIWindow, które tworzysz, jest widokiem kontenera dla twojej aplikacji.

Oprócz ustawiania początkowych widoków, możesz użyć scene(_:willConnectTo:options:) do przywrócenia UI twojej sceny w przypadku, gdy twoja scena rozłączyła się w przeszłości. Na przykład dlatego, że został wysłany do tła. Możesz również odczytać obiekt connectionOptions, aby sprawdzić, czy twoja scena została utworzona z powodu żądania HandOff lub może otworzyć adres URL. Pokażę ci, jak to zrobić w dalszej części tego wpisu na blogu.

Po podłączeniu twojej sceny, następną metodą w cyklu życia twojej sceny jest sceneWillEnterForeground(_:). Ta metoda jest wywoływana, gdy twoja scena przejmie scenę. Może to być, gdy twoja aplikacja przechodzi z tła na pierwszy plan, lub gdy właśnie staje się aktywna po raz pierwszy. Następnie wywoływana jest metoda sceneDidBecomeActive(_:). Jest to punkt, w którym twoja scena jest skonfigurowana, widoczna i gotowa do użycia.

Gdy twoja aplikacja przechodzi na drugi plan, wywoływane są metody sceneWillResignActive(_:) i sceneDidEnterBackground(_:). Nie będę teraz zagłębiał się w te metody, ponieważ ich cel różni się dla każdej aplikacji, a komentarze w szablonie Xcode wykonują całkiem dobrą robotę, wyjaśniając, kiedy te metody są wywoływane. Właściwie to jestem pewien, że sam możesz się zorientować, kiedy te metody są wywoływane.

Najciekawszą metodą jest sceneDidDisconnect(_:). Ilekroć twoja scena jest wysyłana w tło, iOS może zdecydować się na rozłączenie i wyczyszczenie twojej sceny, aby zwolnić zasoby. Nie oznacza to, że twoja aplikacja została zabita lub nie jest już uruchomiona, oznacza to po prostu, że scena przekazana do tej metody nie jest już aktywna i odłączy się od swojej sesji.

Zauważ, że sama sesja również nie jest koniecznie odrzucana, iOS może zdecydować się na ponowne podłączenie sceny do sesji sceny w dowolnym momencie, na przykład gdy użytkownik ponownie wprowadzi daną scenę na pierwszy plan.

Najważniejszą rzeczą do zrobienia w sceneDidDisconnect(_:) jest odrzucenie wszelkich zasobów, których nie musisz trzymać w pobliżu. Mogą to być dane, które można łatwo załadować z dysku lub sieci lub inne dane, które można łatwo odtworzyć. Ważne jest również, aby upewnić się, że zachowujesz wszelkie dane, których nie można łatwo odtworzyć, jak na przykład wszelkie dane wejściowe dostarczone przez użytkownika w scenie, które oczekiwałby, że nadal tam będą, gdy powróci do sceny.

Rozważ aplikację do przetwarzania tekstu, która obsługuje wiele scen. Jeśli użytkownik pracuje w jednej scenie, a następnie w tle, aby przeprowadzić pewne badania w Safari i zmienić swoją muzykę w Spotify, absolutnie oczekiwałby, że cała jego praca nadal istnieje w aplikacji do przetwarzania tekstu, nawet jeśli iOS mógł odłączyć scenę aplikacji do przetwarzania tekstu na chwilę. Aby to osiągnąć, aplikacja musi zachować wymagane dane i powinna zakodować bieżący stan aplikacji w obiekcie NSUserActivity, który można odczytać później w scene(_:willConnectTo:options:), gdy scena zostanie ponownie podłączona.

Ponieważ ten przepływ pracy polegający na podłączaniu, odłączaniu i ponownym podłączaniu scen będzie oddzielał dobre aplikacje od świetnych, przyjrzyjmy się jak możesz zaimplementować przywracanie stanu w swojej aplikacji.

Wykonywanie dodatkowej konfiguracji sceny

Istnieje kilka powodów, dla których musisz wykonać dodatkową konfigurację, gdy scena zostanie ustawiona. Może trzeba będzie otworzyć adres URL, obsłużyć żądanie Handoff lub przywrócić stan. W tej sekcji skupię się głównie na przywracaniu stanu, ponieważ jest to prawdopodobnie najbardziej złożony scenariusz, z którym będziesz musiał sobie poradzić.

Przywracanie stanu rozpoczyna się, gdy twoja scena zostanie odłączona i zostanie wywołana sceneDidDisconnect(_:). W tym momencie ważne jest, aby twoja aplikacja miała już skonfigurowany stan, który może zostać przywrócony później. Najlepszym sposobem, aby to zrobić jest użycie NSUserActivity w twojej aplikacji. Jeśli używasz NSUserActivity do obsługi Handoff, Siri Shortcuts, indeksowania Spotlight i innych, nie masz dużo dodatkowej pracy do wykonania. Jeśli nie używasz jeszcze NSUserActivity, nie martw się. Prosta aktywność użytkownika może wyglądać trochę jak poniżej:

let activity = NSUserActivity(activityType: "com.donnywals.DocumentEdit")activity.userInfo = 

Zauważ, że ta aktywność użytkownika nie jest skonstruowana tak, jak zaleca Apple, jest to bardzo goły przykład mający na celu zilustrowanie przywracania stanu. Aby uzyskać kompletny przewodnik po NSUserActivity, zalecam zapoznanie się z dokumentacją Apple na ten temat.

Gdy nadejdzie czas na dostarczenie aktywności użytkownika, która może zostać przywrócona w późniejszym czasie, system wywołuje metodę stateRestorationActivity(for:) na twoim SceneDelegate. Zauważ, że ta metoda nie jest częścią domyślnego szablonu

func stateRestorationActivity(for scene: UIScene) -> NSUserActivity? { return scene.userActivity}

Wykonanie tej metody powoduje powiązanie aktualnie aktywnej aktywności użytkownika dla sceny z sesją sceny. Pamiętaj, że za każdym razem, gdy scena jest rozłączana, UISceneSession, który jest właścicielem UIScene, nie jest odrzucany, aby umożliwić sesji ponowne połączenie ze sceną. Gdy tak się stanie, ponownie wywoływana jest metoda scene(_:willConnectTo:options:). W tej metodzie masz dostęp do UISceneSession, który jest właścicielem UIScene, więc możesz odczytać stateRestorationActivity sesji i przywrócić stan aplikacji w razie potrzeby:

if let activity = session.stateRestorationActivity, activity.activityType == "com.donnywals.DocumentEdit", let documentId = activity.userInfo as? String { // find document by ID // create document viewcontroller and present it}

Oczywiście, drobne szczegóły tego kodu będą się różnić w zależności od Twojej aplikacji, ale ogólna idea powinna być jasna.

Jeśli twój UISceneSession ma obsługiwać adres URL, możesz sprawdzić urlContexts obiektu connectionOptions, aby znaleźć adresy URL, które twoja scena powinna otworzyć i informacje o tym, jak twoja aplikacja powinna to zrobić:

for urlContext in connectionOptions.urlContexts { let url = urlContext.url let options = urlContext.options // handle url and options as needed}

Obiekt options będzie zawierał informacje o tym, czy twoja scena powinna otworzyć adres URL w miejscu, jaka aplikacja zażądała otwarcia tego adresu URL i inne metadane dotyczące żądania.

Podstawy przywracania stanu w iOS 13 z SceneDelegate są zaskakująco proste, zwłaszcza że jest zbudowany na NSUserActivity, co oznacza, że wiele aplikacji nie będzie musiało wykonać zbyt wiele pracy, aby rozpocząć obsługę przywracania stanu dla swoich scen.

Pamiętaj, że jeśli chcesz mieć wsparcie dla wielu scen dla swojej aplikacji na iPadOS, przywracanie scen jest szczególnie ważne, ponieważ iOS może rozłączyć i ponownie połączyć sceny, gdy przełączają się z pierwszego planu na tło i z powrotem. Zwłaszcza jeśli Twoja aplikacja pozwala użytkownikowi tworzyć lub manipulować obiektami w scenie, użytkownik nie spodziewałby się, że ich praca zniknie, jeśli na chwilę przeniosą scenę na drugi plan.

Podsumowanie

W tym wpisie na blogu wiele się nauczyłeś. Dowiedziałeś się, jakie role AppDelegate i SceneDelegate pełnią w iOS 13 i jak wyglądają ich cykle życia. Teraz wiesz, że AppDelegate jest odpowiedzialny za reagowanie na zdarzenia na poziomie aplikacji, takie jak na przykład uruchomienie aplikacji. Element SceneDelegate jest odpowiedzialny za zdarzenia związane z cyklem życia sceny. Na przykład tworzenie sceny, niszczenie i przywracanie stanu UISceneSession. Innymi słowy, głównym powodem, dla którego Apple dodał UISceneDelegate do iOS 13, było stworzenie dobrego punktu wejścia dla aplikacji z wieloma oknami.

Po zapoznaniu się z podstawami UISceneDelegate, zobaczyłeś bardzo prosty przykład tego, jak wygląda przywracanie stanu w iOS 13 za pomocą UISceneSession i UIScene. Oczywiście, jest o wiele więcej, aby dowiedzieć się, jak Twoja aplikacja zachowuje się, gdy użytkownik tarł wiele UISceneSessions dla swojej aplikacji, i jak te sceny mogą mieć pozostać w synchronizacji lub udostępniać dane.

Jeśli chcesz dowiedzieć się więcej o obsłudze wielu okien dla swojej aplikacji na iPada (lub aplikacji macOS), upewnij się, aby sprawdzić mój post Dodawanie obsługi wielu okien do swojej aplikacji iPadOS. Dzięki za przeczytanie i nie wahaj się dotrzeć na Twittera, jeśli masz jakieś pytania lub opinie dla mnie.

Bądź na bieżąco z moim cotygodniowym biuletynem

Praktyczny Combine

Naucz się wszystkiego, co musisz wiedzieć o Combine i jak możesz go używać w swoich projektach dzięki mojej nowej książce Praktyczny Combine. Otrzymasz trzynaście rozdziałów, Playground i garść przykładowych projektów, aby pomóc Ci dostać się i uruchomić z Combine tak szybko, jak to możliwe.

Książka jest dostępna do pobrania w formie cyfrowej za jedyne 29,99 dolarów!

Pobierz Praktyczny Combine

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.