SceneDelegate 配置和使用

1包券、導讀

iOS13 項目中的SceneDelegate類有什么作用?自從Xcode11發(fā)布以來,當你使用新XCode創(chuàng)建一個新的iOS項目時世吨,SceneDelegate會被默認創(chuàng)建户魏,它到底有什么用呢兽肤。

在本文中套腹,我們將深入探討iOS 13和Xcode 11的一些變化。我們將重點關注SceneDelegate和AppDelegate资铡,以及它們?nèi)绾斡绊慡wiftUI电禀、Storyboard和基于XIB的UI項目。

通過閱讀本文你將了解到:

  • SceneDelegate和AppDelegate的新變化
  • 他們是如何合作引導你的app啟動的
  • 在純手寫App中使用SceneDelegate
  • 在Storyboards 和 SwiftUI項目中使用SceneDelegate
  • 不是用SceneDelegate的話怎么處理

2笤休、AppDelegate回顧

你可能對AppDelegate已經(jīng)熟悉尖飞,他是iOS app的入口,{application(_:didFinishLaunchingWithOptions:)}
是你的app啟動后系統(tǒng)調(diào)用的第一個函數(shù)店雅。

AppDelegate類實現(xiàn)了UIKit庫中的UIApplicationDelegate 協(xié)議政基。而到了iOS13 AppDelegate的角色將會發(fā)生變化,后面我們會詳細討論闹啦。

下面是你在iOS12中一般會在AppDelegate中做的事情:

  • 創(chuàng)建app的第一個view controller也就是 rootViewController
  • 配置并啟動一些像日志記錄和云服務之類的組件
  • 注冊推送通知處理程序沮明,并響應發(fā)送到app的推送通知
  • 響應應用程序生命周期事件,例如進入后臺窍奋,恢復應用程序或退出應用程序(終止)
//iOS12及以前荐健,使用Storyboards的app,AppDelegate很簡單琳袄。 像這樣:
func application(_ application: UIApplication, didFinishLaunchingWithOptions 
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool{
    return true
}

//一個使用XIB的簡單應用看起來像這樣:
func application(_ application: UIApplication, didFinishLaunchingWithOptions 
launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool{   
    let timeline = TimelineViewController()
    let navigation = UINavigationController(rootViewController: timeline)

    let frame = UIScreen.main.bounds
    window = UIWindow(frame: Framew

    window!.rootViewController = navigation
    window!.makeKeyAndVisible()

    return true
}

在上面的代碼中江场,我們創(chuàng)建一個ViewController,并將其放在navigation controller中。然后將其分配給UIWindow對象的rootViewController屬性窖逗。 這個window對象是AppDelegate的屬性址否,它是我們的應用的一個窗口。

應用程序的window是一個重要的概念碎紊。 本質(zhì)上佑附,窗口就是應用程序,大多數(shù)iOS應用程序只有一個窗口仗考。 它包含您應用的用戶界面(UI)音同,將事件調(diào)度到視圖,并提供了一個主要背景層來顯示您的應用內(nèi)容痴鳄。 從某種意義上說瘟斜,“ Windows”的概念就是微軟定義的窗口,而在iOS上痪寻,這個概念沒有什么不同螺句。

如果“窗口”的概念仍然不了解,請查看iPhone上的應用程序切換器橡类。 雙擊Home鍵或從iPhone底部向上滑動蛇尚,然后您會看到當前正在運行的應用程序的窗口。 這就是應用程序切換器顾画。

3取劫、SceneDelegate使用

在iOS 13(及以后版本)上匆笤,SceneDelegate將負責AppDelegate的某些功能。 最重要的是谱邪,window(窗口)的概念已被scene(場景)的概念所代替炮捧。 一個應用程序可以具有不止一個場景,而一個場景現(xiàn)在可以作為您應用程序的用戶界面和內(nèi)容的載體(背景)惦银。

尤其是一個具有多場景的App的概念很有趣咆课,因為它使您可以在iOS和iPadOS上構建多窗口應用程序。 例如扯俱,文檔編輯器App中的每個文本文檔都可以有自己的場景书蚪。 用戶還可以創(chuàng)建場景的副本,同時運行一個應用程序的多個實例(類似多開)迅栅。

3.1 SceneDelegate相關文件介紹

在Xcode 11中有三個地方可以明顯地看到SceneDelegate的身影:

  • 現(xiàn)在殊校,一個新的iOS項目會自動創(chuàng)建一個SceneDelegate類,其中包括我們熟悉的生命周期事件读存,例如active为流,resign和disconnect。
  • AppDelegate類中多了兩個與“scene sessions”相關的新方法:application(_:configurationForConnecting:options:)application(_:didDiscardSceneSessions:)
  • Info.plist文件中提供了”Application Scene Manifest“配置項宪萄,用于配置App的場景艺谆,包括它們的場景配置名榨惰,delegate類名和storyboard

3.1.1 SceneDelegate類

import UIKit

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, 
                             options connectionOptions: UIScene.ConnectionOptions) {
        //1拜英、SceneDelegate的最重要的函數(shù)是:`scene(_:willConnectTo:options:)`。 
        //  在某種程度上琅催,它與iOS 12上的 `application(_:didFinishLaunchingWithOptions:)` 函數(shù)的作用最相似居凶。
        //  當將場景添加到app中時`scene(_:willConnectTo:options:)`函數(shù)會被調(diào)用的,因此這里是配置場景的最理想地方藤抡。 
        //2侠碧、這里需要特別注意的是,“SceneDelegate”采用了協(xié)議模式缠黍,并且這個delegate通常會響應任何場景弄兜。 
        //   使用一個Delegate來配置App中的所有場景。

        //手動地設置視圖控制器堆棧
        if let windowScene = scene as? UIWindowScene {
            window = UIWindow(windowScene: windowScene)

            let vc = ViewController()
            let navigation = UINavigationController(rootViewController: vc)

            window.rootViewController = navigation
            
            window.makeKeyAndVisible()
        }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // 當場景與app斷開連接是調(diào)用(注意瓷式,以后它可能被重新連接)
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // 當用戶開始與場景進行交互(例如從應用切換器中選擇場景)時替饿,會調(diào)用
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // 當用戶停止與場景交互(例如通過切換器切換到另一個場景)時調(diào)用
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // 當場景變成活動窗口時調(diào)用,即從后臺狀態(tài)變成開始或恢復狀態(tài)
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // 當場景進入后臺時調(diào)用贸典,即該應用已最小化但仍存活在后臺中
    }
}

3.1.2 AppDelegate 中的 SceneSessions

import UIKit

@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

    // MARK: UISceneSession Lifecycle
    //在iOS13中AppDelegate中有兩個管理Senen Session的代理函數(shù)视卢。
    //在您的應用創(chuàng)建scene(場景)后,“scene session”對象將跟蹤與該場景相關的所有信息廊驼。
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        // 會返回一個創(chuàng)建場景時需要的UISceneConfiguration對象
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
        // 當用戶通過“應用切換器”關閉一個或多個場景時會被調(diào)用
        // 您可以在該函數(shù)中銷毀場景所使用的資源据过,因為不會再需要它們惋砂。
        // 了解application(_:didDiscardSceneSessions:)與sceneDidDisconnect(_ :)的區(qū)別很重要,后者僅在場景斷開連接時調(diào)用绳锅,不會被丟棄西饵,它可能會重新連接。
        // 而application(_:didDiscardSceneSessions:)發(fā)生在使用【應用程序切換器】退出場景時鳞芙。
    }
}

目前罗标,SceneSession被用于指定場景,例如“外部顯示” 或“ CarPlay” 积蜻。 它還可用于還原場景的狀態(tài)闯割,如果您想使用【狀態(tài)還原】,SceneSession將非常有用竿拆。 狀態(tài)還原允許您在應用啟動之間保留并重新創(chuàng)建UI宙拉。 您還可以將用戶信息存儲到場景會話中,它是一個可以放入任何內(nèi)容的字典丙笋。

3.1.3 Info.plist 中的Application Scene Manifest

您的應用支持的每個場景都需要在“Application Scene Manifest”(應用場景清單)中聲明谢澈。 簡而言之,清單列出了您的應用支持的每個場景御板。 大多數(shù)應用程序只有一個場景锥忿,但是您可以創(chuàng)建更多場景,例如用于響應推送通知或特定操作的特定場景怠肋。

Application Scene Manifest清單是Info.plist文件的一項敬鬓,都知道該文件包含App的配置信息。 Info.plist包含諸如App的名稱笙各,版本钉答,支持的設備方向以及現(xiàn)在支持的不同場景等配置。

請務必注意杈抢,您聲明的是會話的“類型”数尿,而不是會話實例。 您的應用程序可以支持一個場景惶楼,然后創(chuàng)建該場景的副本右蹦,來實現(xiàn)【多窗口】應用程序。

Info.plist 中的Application Scene Manifest

在上圖中歼捐,您會看到Application Scene Manifest 這一條何陆。 在它下面一條是Enable Multiple Windows,需要將其設置為“ YES”以支持多個窗口窥岩。 再往下Application Session Role的值是一個數(shù)組甲献,用于在應用程序中聲明場景。 你也可以在數(shù)組中添加一條【外部屏幕】的場景聲明颂翼。

最重要的信息保存在Application Session Role數(shù)組中晃洒。 從中我們可以看到以下內(nèi)容:

  • Configuration的名稱慨灭,必須是唯一的
  • 場景的代理類名,通常為SceneDelegate球及。
  • 場景用于創(chuàng)建初始UI的storyboard名稱
    Storyboard名稱這一項可能使您想起Main Interface設置氧骤,該設置可以在Xcode 12項目的Project Properties配置中找到。 現(xiàn)在吃引,在iOS應用中筹陵,你可以在此處設置或更改主Storyboard名稱。

AppDelegate中的SceneDelegate镊尺、UISceneSession和Application Scene Manifest是如何一起創(chuàng)建多窗口應用的呢朦佩?

  • 首先,我們看SceneDelegate類庐氮。 它管理場景的生命周期语稠,處理各種響應,諸如 sceneDidBecomeActive(_:)sceneDidEnterBackground(_:)之類的事件弄砍。
  • 然后扔傅,我們再看看AppDelegate類中的新函數(shù)蒜撮。 它管理場景會話(scene sessions),提供場景的配置數(shù)據(jù)先紫,并響應用戶丟棄場景的事件倘屹。
  • 最后盐肃,我們看了一下Application Scene Manifest帚屉。 它列出了您的應用程序支持的場景渤愁,并將它們連接到delegate類并初始化storyboard。

3.2 在SwiftUI中使用Scene Delegate

不久將來瞳收,SwiftUI將是創(chuàng)建iOS項目最簡單的方法碉京。 簡言之厢汹,SwiftUI應用程序主要依靠SceneDelegate來設置應用程序的初始UI螟深。

3.2.1 配置

  • Application Scene Manifest
    ~ 特別注意,配置中沒有設置“Storyboard Name”這一項烫葬。 請記住界弧,如果要支持多個窗口,則需要將Enable Multiple Windows設置為YES ~
在SwiftUI中Application Scene Manifest配置
  • AppDelegate
    我們將跳過“ AppDelegate”搭综,因為它相當標準垢箕。在SwiftUI項目中,只會返回“true”兑巾。

  • SceneDelegate
    正如我們之前討論的条获,SceneDelegate負責設置您應用中的場景,以及設置首個頁面蒋歌。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {

        let contentView = ContentView()

        if let windowScene = scene as? UIWindowScene {
            let window = UIWindow(windowScene: windowScene)
            window.rootViewController = UIHostingController(rootView: contentView)
            self.window = window
            window.makeKeyAndVisible()
        }
    }
}
上面的代碼中發(fā)生了什么帅掘?

1委煤、首先,必須明確的是 在將新場景添加到應用中后 會調(diào)用 'scene(_:willConnectTo:options:) '代理函數(shù)修档。 
  它提供了一個'scene'對象和一個'session'碧绞。 這個'UIWindowScene'對象是由應用創(chuàng)建的,您無需進行其他操作吱窝。
2讥邻、其次,'window'屬性會在這里用到院峡。 App仍然使用'UIWindow'對象兴使,但現(xiàn)在它們已成為'scene'(場景)的一部分。
  在'if let'代碼塊中照激,您可以清楚地看到如何使用'scene'來初始化'UIWindow'對象的鲫惶。
3、然后是設置'window'的'rootViewController'实抡,將'window'實例分配給了場景的'window'屬性欠母,并且設置窗口'makeKeyAndVisible'為true,即將該窗口置于App的前面吆寨。
  接著為SwiftUI項目創(chuàng)建了'ContentView'實例赏淌,并通過使用'UIHostingController'將其添加為根視圖控制器。 
  該控制器用于將基于SwiftUI的視圖顯示在屏幕上啄清。
4六水、最后但并非不重要的一點,值得注意的是辣卒,'UIScene'的實例化對象'scene'實際上是'UIWindowScene'類型的對象掷贾。這就是'as?'對可選類型轉(zhuǎn)換的原因。

所有這些看起來似乎很復雜荣茫,但是從高層次的概述來看想帅,這很簡單:

當'scene(_:willConnectTo:options:)'被調(diào)用時,'SceneDelegate'會在正確的時間配置場景啡莉。
'AppDelegate'和'Manifest'的默認配置港准,他們沒有涉及'storyboard'的任何東西。
'scene(_:willConnectTo:options :)'函數(shù)內(nèi)咧欣,創(chuàng)建一個SwiftUI視圖浅缸,將其放置在托管控制器中,
然后將控制器分配給'window'屬性的根視圖控制器魄咕,并將該窗口放置在應用程序UI的前面 衩椒。

您可以通過選擇File(文件)→New(新建)→Project(項目)來建立一個基本的Xcode 11項目。 然后,選擇Single View App, 在User Interface處選擇SwiftUI來創(chuàng)建一個SwiftUI項目

3.3 在Storyboards項目中使用SceneDelegate

Storyboards和XIB是為iOS應用程序構建UI的有效方法毛萌。 在iOS 13梢什、14也是如此。 在將來朝聋,我們將看到更多的SwiftUI應用嗡午,但目前,Storyboards更常見冀痕。

有趣的是荔睹,即使有了SceneDelegate,通過Storyboards創(chuàng)建iOS項目你也不需要做任何額外的事情 只需選擇File → New → Project言蛇。 然后僻他,選擇Single View App。 最后腊尚,為 User Interface 處選擇 Storyboard 吨拗,就完成了。

設置方法如下:

  • 如我們前面提到過的婿斥,您可以在Info.plist中的Application Scene Manifest中找到Main storyboard的設置地方劝篷。
  • 默認情況下,AppDelegate將使用默認的UISceneConfiguration民宿。
  • SceneDelegate會設置一個UIWindow對象娇妓,并使用Main.storyboard來創(chuàng)建初始UI。

3.3 純代碼編寫UI

許多開發(fā)人員喜歡手寫UI活鹰,而隨著SwiftUI的興起哈恰,使用SwiftUI手寫代碼將會越來越常見。 如果您不使用storyboards志群,而使用XIB創(chuàng)建應用程序UI着绷,該怎么辦?

首先锌云,AppDelegateApplication Scene Manifest中保持默認值荠医。
我們不使用storyboard,所以需要在SceneDelegate類的scene(_:willConnectTo:options:)函數(shù)中設置初始視圖控制器宾抓。
然后子漩,刪除info.plist中的Main storyboard file base name條目和Application Scene Manifest下的Storyboard Name條目,Main.storyboard文件留與不留看你心意石洗。
大功告成。

class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
    {
        if let windowScene = scene as? UIWindowScene {

            let window = UIWindow(windowScene: windowScene)
            let timeline = TimelineViewController()

            let navigation = UINavigationController(rootViewController: timeline)
            window.rootViewController = navigation

            self.window = window
            window.makeKeyAndVisible()
        }
    }
}

4紧显、不使用SceneDelegate

傳送門:如何不使用SceneDelegate

參考文章:

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末讲衫,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌涉兽,老刑警劉巖招驴,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枷畏,居然都是意外死亡别厘,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進店門拥诡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來触趴,“玉大人,你說我怎么就攤上這事渴肉∪吲常” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵仇祭,是天一觀的道長披蕉。 經(jīng)常有香客問我,道長乌奇,這世上最難降的妖魔是什么没讲? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮礁苗,結果婚禮上食零,老公的妹妹穿的比我還像新娘。我一直安慰自己寂屏,他們只是感情好贰谣,可當我...
    茶點故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著迁霎,像睡著了一般吱抚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上考廉,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天秘豹,我揣著相機與錄音,去河邊找鬼昌粤。 笑死既绕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的涮坐。 我是一名探鬼主播凄贩,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼袱讹!你這毒婦竟也來了疲扎?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椒丧,沒想到半個月后壹甥,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡壶熏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年句柠,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棒假。...
    茶點故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡溯职,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出淆衷,到底是詐尸還是另有隱情缸榄,我是刑警寧澤,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布祝拯,位于F島的核電站甚带,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏佳头。R本人自食惡果不足惜鹰贵,卻給世界環(huán)境...
    茶點故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望康嘉。 院中可真熱鬧碉输,春花似錦、人聲如沸亭珍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽肄梨。三九已至阻荒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間众羡,已是汗流浹背侨赡。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留粱侣,地道東北人羊壹。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像齐婴,于是被迫代替她去往敵國和親油猫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,465評論 2 348