Understanding the iOS 13 Scene Delegate

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

Kun luot uuden projektin Xcode 11:ssä, saatat huomata jotakin, mitä et ole nähnyt aiemmin. Sen sijaan, että Xcode loisi vain AppDelegate.swift-tiedoston, ViewController.swift-tiedoston, storyboardin ja joitain muita tiedostoja, se luo sinulle nyt uuden tiedoston; SceneDelegate.swift-tiedoston. Jos et ole koskaan ennen nähnyt tätä tiedostoa, voi olla melko hämmentävää ymmärtää, mikä se on ja miten sinun on tarkoitus käyttää tätä uutta scene-delegaattia sovelluksessasi.

Tämän viikon blogikirjoituksen loppuun mennessä tiedät:

  • Mihin scene-delegaattia käytetään.
  • Miten voit toteuttaa scene-delegaatin tehokkaasti.
  • Miksi scene-delegaatti on tärkeä osa iOS 13:sta.

Hyppäämmekö heti asiaan?

Uuden Xcode-projektin mallin tutkiminen

Kun luot uuden Xcode-projektin, voit valita, haluatko käyttää SwiftUI:ta vai Storyboardia. Riippumatta siitä, minkälaisen valinnan tässä teet, Xcode luo uudenlaisen projektimallin, jonka pohjalta voit rakentaa. Tutustumme tarkemmin SceneDelegate.swift– ja AppDelegate.swift-tiedostoihin seuraavassa kappaleessa, nyt on tärkeää, että ymmärrät, että Xcode on luonut nämä tiedostot puolestasi.

Näiden kahden delegaattitiedoston lisäksi Xcode tekee jotain hieman hienovaraisempaa. Katso tarkkaan Info.plist-tiedostoasi. Sinun pitäisi nähdä uusi avain nimeltä Application Scene Manifest, jonka sisältö on seuraavan kuvan kaltainen:

Kuvakaappaus Info.plist-tiedoston scene-manifestista

Kuvakaappaus Info.plist-tiedoston scene-manifestista

Tämä scene-manifesti määrittää nimen ja delegaattiluokan kohtauksellesi. Huomaa, että nämä ominaisuudet kuuluvat joukkoon (Application Session Role), mikä viittaa siihen, että sinulla voi olla useita kokoonpanoja Info.plist. Paljon tärkeämpi avain, jonka olet ehkä jo huomannut yllä olevasta kuvakaappauksesta, on Enable Multiple Windows. Tämä ominaisuus on oletusarvoisesti asetettu arvoon NO. Asettamalla tämän ominaisuuden arvoksi YES käyttäjät voivat avata useita ikkunoita sovelluksestasi iPadOS:ssä (tai jopa macOS:ssä). Mahdollisuus käyttää useita iOS-sovelluksen ikkunoita vierekkäin on valtava ero tähän asti käyttämäämme yhden ikkunan ympäristöön, ja mahdollisuus käyttää useita ikkunoita on koko syy siihen, että sovelluksemme elinkaarta ylläpidetään nyt kahdessa paikassa yhden sijasta.

Katsotaanpa tarkemmin AppDelegate:tä ja SceneDelegate:tä, jotta ymmärretään paremmin, miten nämä kaksi delegaattia työskentelevät yhdessä mahdollistaakseen tuen useille ikkunoille.

AppDelegaten ja SceneDelegaten roolien ymmärtäminen

Jos olet rakentanut sovelluksia ennen iOS 13:a, tunnet luultavasti AppDelegate:n ainoana paikkana, joka tekee melkeinpä kaiken, mikä liittyy sovelluksen käynnistämiseen, etualalle asettamiseen, taustalle asettamiseen, ja sitten vielä enemmän. iOS 13:ssa Apple on siirtänyt osan AppDelegate:n vastuista SceneDelegate:ään. Katsotaanpa lyhyesti kumpaakin näistä kahdesta tiedostosta.

AppDelegaten vastuut

AppDelegate on edelleen sovelluksen pääasiallinen lähtöpiste iOS 13:ssa. Apple kutsuu AppDelegate-metodeja useisiin sovellustason elinkaaritapahtumiin. Applen oletusmallissa on kolme metodia, joita Apple pitää tärkeinä käyttää:

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

Näissä metodeissa on jonkin verran selostusta, joka oikeastaan kuvaa niiden toimintaa riittävän yksityiskohtaisesti, jotta niiden toiminnan ymmärtää. Käydään ne kuitenkin nopeasti läpi.

Kun sovellus on juuri käynnistetty, kutsutaan func application(_:didFinishLaunchingWithOptions:) -> Bool. Tätä metodia käytetään sovelluksen asennuksen suorittamiseen. iOS 12:ssa tai sitä aikaisemmissa versioissa olet ehkä käyttänyt tätä metodia luodaksesi ja konfiguroidaksesi UIWindow-objektin ja osoittaaksesi UIViewController-instanssin ikkunalle, jotta se ilmestyisi.

Jos sovelluksesi käyttää kohtauksia, AppDelegate ei enää vastaa tämän tekemiseen. Koska sovelluksellasi voi nyt olla useita ikkunoita eli UISceneSession aktiivisia, ei ole kovin järkevää hallita yhden ikkunan objektia AppDelegate:ssä.

func application(_:configurationForConnecting:options:) -> UISceneConfigurationKutsutaan aina, kun sovelluksesi odotetaan toimittavan uuden kohtauksen eli ikkunan iOS:lle näytettäväksi. Huomaa, että tätä metodia ei kutsuta, kun sovelluksesi käynnistyy aluksi, vaan sitä kutsutaan vain uusien kohtausten saamiseksi ja luomiseksi. Tutustumme syvällisemmin useiden kohtausten luomiseen ja hallintaan myöhemmässä blogikirjoituksessa.

AppDelegate-mallin viimeinen metodi on func application(_:didDiscardSceneSessions:). Tätä metodia kutsutaan aina, kun käyttäjä hylkää kohtauksen, esimerkiksi pyyhkäisemällä sen pois multitasking-ikkunassa tai jos se tehdään ohjelmallisesti. Jos sovelluksesi ei ole käynnissä, kun käyttäjä tekee näin, tätä metodia kutsutaan jokaisen hylätyn kohtauksen kohdalla pian sen jälkeen, kun func application(_:didFinishLaunchingWithOptions:) -> Bool on kutsuttu.

Näiden oletusmetodien lisäksi AppDelegate-metodia voidaan vielä käyttää avaamaan URL-osoitteita, nappaamaan muistivaroituksia, havaitsemaan, milloin sovelluksesi päättyy, muuttuiko laitteen kello merkittävästi, havaitsemaan, milloin käyttäjä on ilmoittautunut etämuistioksiantoihin ja paljon muuta.

Vinkki:
On tärkeää huomata, että jos käytät tällä hetkellä AppDelegate:ää sovelluksesi tilarivin ulkoasun hallintaan, sinun on ehkä tehtävä joitakin muutoksia iOS 13:ssa. Useat tilapalkkiin liittyvät metodit on poistettu käytöstä iOS 13:ssa.

Nyt kun meillä on parempi kuva siitä, mitkä ovat AppDelegate:n uudet tehtävät, katsotaanpa uutta SceneDelegate.

SceneDelegaatin vastuualueet

Kun ajatellaan, että AppDelegate on objekti, joka vastaa sovelluksesi elinkaaresta, SceneDelegate vastaa siitä, mitä näytöllä näytetään; kohtauksista tai ikkunoista. Ennen kuin jatkamme, luodaan hieman kohtauksiin liittyvää sanastoa, koska jokainen termi ei tarkoita sitä, mitä luulet sen tarkoittavan.

Kun olet tekemisissä kohtausten kanssa, se, mikä näyttää käyttäjälle ikkunalta, on itse asiassa nimeltään UIScene, jota hallinnoi UISceneSession. Kun siis viittaamme ikkunoihin, viittaamme todellisuudessa UISceneSession-objekteihin. Yritän pitää kiinni tästä terminologiasta niin paljon kuin mahdollista tämän blogikirjoituksen aikana.

Nyt kun olemme samalla sivulla, katsotaanpa SceneDelegate.swift-tiedostoa, jonka Xcode loi luodessaan projektimme.

Tiedostossa SceneDelegate.swift on oletusarvoisesti useita metodeja:

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

Näiden metodien pitäisi näyttää hyvin tutuilta, jos tunnet ennen iOS 13:aa olleen AppDelegate. Katsotaanpa ensin scene(_:willConnectTo:options:), tämä metodi näyttää luultavasti sinulle vähiten tutulta ja se on ensimmäinen metodi, jota kutsutaan UISceneSession:n elinkaaren aikana.

scene(_:willConnectTo:options:):n oletustoteutus luo alkuperäisen sisällönäkymän (ContentView, jos käytät SwiftUI:ta), luo uuden UIWindow:n, asettaa ikkunan rootViewController:n ja tekee tästä ikkunasta avainikkunan. Voit ajatella tätä ikkunaa ikkunaksi, jonka käyttäjäsi näkee. Näin ei valitettavasti ole. Ikkunat ovat olleet olemassa jo ennen iOS 13:a, ja ne edustavat näkymäikkunaa, jossa sovelluksesi toimii. Joten UISceneSession ohjaa näkyvää ikkunaa, jonka käyttäjä näkee, ja luomasi UIWindow on sovelluksesi konttinäkymä.

Aloitusnäkymien määrittämisen lisäksi voit käyttää scene(_:willConnectTo:options:):tä palauttamaan kohtauksen käyttöliittymän, jos kohtauksesi on aiemmin katkaissut yhteyden. Esimerkiksi siksi, että se lähetettiin taustalle. Voit myös lukea connectionOptions-objektin nähdäksesi, onko kohtauksesi luotu HandOff-pyynnön vuoksi tai ehkä URL-osoitteen avaamiseksi. Näytän, miten tämä tehdään myöhemmin tässä blogikirjoituksessa.

Kun kohtauksesi on muodostanut yhteyden, seuraava menetelmä kohtauksesi elinkaaressa on sceneWillEnterForeground(_:). Tätä metodia kutsutaan, kun kohtauksesi astuu näyttämölle. Tämä voi tapahtua, kun sovelluksesi siirtyy taustalta etualalle tai jos se on juuri aktivoitumassa ensimmäistä kertaa. Seuraavaksi kutsutaan sceneDidBecomeActive(_:). Tässä vaiheessa kohtauksesi on asetettu, näkyvissä ja valmis käytettäväksi.

Kun sovelluksesi siirtyy taustalle, kutsutaan sceneWillResignActive(_:) ja sceneDidEnterBackground(_:). En käsittele näitä metodeja nyt, koska niiden tarkoitus vaihtelee jokaisessa sovelluksessa, ja Xcode-mallin kommentit selittävät melko hyvin, milloin näitä metodeja kutsutaan. Itse asiassa voit varmasti itsekin selvittää, milloin näitä metodeja kutsutaan.

Mielenkiintoisempi metodi on sceneDidDisconnect(_:). Aina kun kohtauksesi lähetetään taustalle, iOS saattaa päättää katkaista yhteyden ja tyhjentää kohtauksesi vapauttaakseen resursseja. Tämä ei tarkoita, että sovelluksesi olisi tapettu tai että se ei olisi enää käynnissä, se tarkoittaa vain sitä, että tähän metodiin välitetty kohtaus ei ole enää aktiivinen ja se katkaisee yhteyden istuntoonsa.

Huomaa, että itse istuntoa ei välttämättä myöskään hävitetä, vaan iOS saattaa päättää yhdistää kohtauksen uudelleen kohtausistuntoon milloin tahansa, esimerkiksi kun käyttäjä tuo tietyn kohtauksen uudelleen etualalle.

Tärkeintä metodin sceneDidDisconnect(_:) kohdalla on hävittää kaikki resurssit, joita ei tarvitse pitää mukana. Tämä voi olla dataa, joka on helposti ladattavissa levyltä tai verkosta, tai muuta dataa, jonka voi helposti luoda uudelleen. On myös tärkeää varmistaa, että säilytät kaikki tiedot, joita ei voi helposti luoda uudelleen, kuten esimerkiksi kaikki käyttäjän kohtauksessa antamat syötteet, joiden hän odottaisi olevan edelleen olemassa, kun hän palaa kohtaukseen.

Harkitse tekstinkäsittelysovellusta, joka tukee useita kohtauksia. Jos käyttäjä työskentelee yhdessä kohtauksessa ja taustoittaa sen sitten tehdäkseen tutkimusta Safarissa ja vaihtaakseen musiikkia Spotifyssa, hän ehdottomasti odottaisi, että kaikki hänen työnsä on edelleen olemassa tekstinkäsittelysovelluksessa, vaikka iOS olisi ehkä irrottanut tekstinkäsittelysovelluksen kohtauksen hetkeksi. Tämän saavuttamiseksi sovelluksen on säilytettävä tarvittavat tiedot, ja sen olisi koodattava sovelluksen nykyinen tila NSUserActivity-objektiin, joka voidaan lukea myöhemmin scene(_:willConnectTo:options:):ssä, kun kohtaus kytketään uudelleen.

Koska tämä kohtausten yhdistämisen, irrottamisen ja uudelleen yhdistämisen työnkulku erottaa hyvät sovellukset loistavista, katsotaanpa, miten voit toteuttaa tilan palauttamisen sovelluksessasi.

Skenen lisäasetusten suorittaminen

On useita syitä siihen, että joudut suorittamaan lisäasetuksia, kun kohtaus asetetaan. Sinun on ehkä avattava URL-osoite, käsiteltävä Handoff-pyyntö tai palautettava tila. Tässä osiossa keskityn enimmäkseen tilan palauttamiseen, koska se on mahdollisesti monimutkaisin skenaario, jota saatat joutua käsittelemään.

Tilan palauttaminen alkaa, kun kohtaus katkaistaan ja sceneDidDisconnect(_:) kutsutaan. Tässä vaiheessa on tärkeää, että sovelluksellasi on jo valmiiksi tila, joka voidaan palauttaa myöhemmin. Paras tapa tehdä tämä on käyttää sovelluksessasi NSUserActivity. Jos käytät NSUserActivity:tä tukemaan Handoffia, Sirin pikanäppäimiä, Spotlight-indeksointia ja muuta, sinulla ei ole paljon ylimääräistä työtä tehtävänä. Jos et vielä käytä NSUserActivity:tä, älä huoli. Yksinkertainen käyttäjäaktiviteetti voi näyttää hieman seuraavalta:

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

Huomaa, että tämä käyttäjäaktiviteetti ei ole rakenteeltaan sellainen kuin Apple suosittelee, vaan se on hyvin pelkkä esimerkki, jonka tarkoituksena on havainnollistaa tilan palauttamista. Jos haluat täydellisen oppaan NSUserActivity:stä, suosittelen tutustumaan Applen dokumentaatioon tästä aiheesta.

Kun tulee aika tarjota käyttäjäaktiviteetti, joka voidaan palauttaa myöhemmin, järjestelmä kutsuu SceneDelegate-metodia stateRestorationActivity(for:). Huomaa, että tämä metodi ei ole osa oletusmallia

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

Tämän tekeminen liittää kohtauksen parhaillaan aktiivisen käyttäjäaktiviteetin kohtausistuntoon. Muista, että aina kun kohtauksen yhteys katkaistaan, UISceneSession, joka omistaa UIScene, ei hävitetä, jotta istunto voi muodostaa uudelleen yhteyden kohtaukseen. Kun näin tapahtuu, scene(_:willConnectTo:options:) kutsutaan uudelleen. Tässä metodissa sinulla on pääsy UIScene:n omistavaan UISceneSession:iin, joten voit lukea istunnon stateRestorationActivity:n ja palauttaa sovelluksen tilan tarpeen mukaan:

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}

Tämän koodin hienot yksityiskohdat vaihtelevat tietysti sovelluksesi mukaan, mutta yleisidean pitäisi olla selvä.

Jos UISceneSession:n odotetaan käsittelevän URL-osoitteita, voit tarkastaa connectionOptions-objektin urlContexts:n löytääksesi URL-osoitteet, jotka kohtauksesi pitäisi avata, ja tietoa siitä, miten sovelluksesi pitäisi tehdä tämä:

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

Objekti options sisältää tietoa siitä, pitäisikö kohtauksesi avata URL-osoite paikan päällä, mikä sovellus pyysi URL-osoitteen avaamista, sekä muuta metatietoa pyynnöstä.

Tilan palauttamisen perusteet iOS 13:ssa SceneDelegate:n avulla ovat yllättävän suoraviivaisia, varsinkin kun se on rakennettu NSUserActivity:n varaan, mikä tarkoittaa, että monien sovellusten ei tarvitse tehdä liikaa töitä alkaakseen tukea tilan palauttamista kohtauksilleen.

Kannattaa muistaa, että jos haluat sovelluksellesi tuen useille kohtauksille iPadOS:ssä, kohtauksen palauttaminen on erityisen tärkeää, koska iOS saattaa katkaista ja yhdistää kohtauksesi uudelleen, kun ne siirtyvät etualalta taustalle ja takaisin. Etenkin jos sovelluksesi antaa käyttäjän luoda tai käsitellä objekteja kohtauksessa, käyttäjä ei odota, että hänen työnsä katoaa, jos hän siirtää kohtauksen hetkeksi taustalle.

Yhteenveto

Tässä blogikirjoituksessa olet oppinut paljon. Olet oppinut, mitä rooleja AppDelegate ja SceneDelegate täyttävät iOS 13:ssa ja miltä niiden elinkaari näyttää. Tiedät nyt, että AppDelegate vastaa reagoimisesta sovellustason tapahtumiin, kuten esimerkiksi sovelluksen käynnistämiseen. SceneDelegate vastaa kohtauksen elinkaareen liittyvistä tapahtumista. Esimerkiksi UISceneSession:n kohtauksen luomisesta, tuhoamisesta ja tilan palauttamisesta. Toisin sanoen Applen tärkein syy lisätä UISceneDelegate iOS 13:een oli luoda hyvä lähtökohta moniikkunasovelluksille.

Kun opit UISceneDelegate:n perusteet, näit hyvin yksinkertaisen esimerkin siitä, miltä tilan palauttaminen näyttää iOS 13:ssa UISceneSession:n ja UIScene:n avulla. Tietenkin on paljon enemmän opittavaa siitä, miten sovelluksesi käyttäytyy, kun käyttäjä luo sovelluksellesi useita UISceneSession-ikkunoita, ja miten näiden kohtausten on ehkä pysyttävä synkronoituina tai jaettava tietoja.

Jos haluat oppia lisää useiden ikkunoiden tukemisesta iPad-sovelluksessasi (tai macOS-sovelluksessasi), tutustu postaukseeni Useiden ikkunoiden tuen lisääminen iPadOS-sovellukseesi. Kiitos lukemisesta, äläkä epäröi ottaa yhteyttä Twitterissä, jos sinulla on kysyttävää tai palautetta minulle.

Otaudu ajan tasalle viikoittaisella uutiskirjeelläni

Practical Combine

Opi uudesta kirjastani Practical Combine kaikki, mitä sinun tarvitsee tietää Combinesta ja siitä, miten voit käyttää sitä projekteissasi. Saat kolmetoista lukua, leikkikentän ja kourallisen esimerkkiprojekteja, joiden avulla pääset käyttämään Combinea mahdollisimman pian.

Kirja on saatavana digitaalisena latauksena vain 29,99 dollarilla!

Hanki Practical Combine

Vastaa

Sähköpostiosoitettasi ei julkaista.