iOS13新特性 - SceneDelegate

SceneDelegate是為了支持 iOS13之后的 iPadOS 多窗口口而退出的茂蚓。Xcode11 默認(rèn)會(huì)創(chuàng)建通過(guò) UIScene 管理多個(gè) UIWindow 的應(yīng)用沥阱,工程中除了 AppDelegate 外會(huì)多一個(gè) SceneDelegate伐憾。并且 AppDelegate.h 不再有 window 屬性篙螟,window 屬性被定義在了 SceneDelegate.h 中芹扭,SceneDelegate 負(fù)責(zé)原 AppDelegate 的 UI 生命周期部分的職責(zé)吨娜。

  • iOS13之前
    AppDelegate的職責(zé)全權(quán)處理 App 生命周期和 UI 的生命周期脓匿。


    image.png

這種模式完全沒(méi)有問(wèn)題,因?yàn)橹挥幸粋€(gè)進(jìn)程宦赠,只有一個(gè)與這個(gè)進(jìn)程對(duì)應(yīng)的用戶(hù)界面陪毡。

  • iOS13 之后
    AppDelegate 的職責(zé)是處理 App 的生命周期;
    新增的 SceneDelegate 是處理 UI 的生命周期勾扭。
image.png
image.png
  • Xcode11 新建項(xiàng)目的 AppDelegate 文件
import UIKit

@UIApplicationMain
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
    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
        
        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
    }

    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {

    }
}

  • Xcode11 新建項(xiàng)目的 SceneDelegate 文件
class SceneDelegate: UIResponder, UIWindowSceneDelegate {

    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        guard let _ = (scene as? UIWindowScene) else { return }
    }

    func sceneDidDisconnect(_ scene: UIScene) {
        // Called as the scene is being released by the system.
        // This occurs shortly after the scene enters the background, or when its session is discarded.
        // Release any resources associated with this scene that can be re-created the next time the scene connects.
        // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // Called when the scene has moved from an inactive state to an active state.
        // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // Called when the scene will move from an active state to an inactive state.
        // This may occur due to temporary interruptions (ex. an incoming phone call).
    }

    func sceneWillEnterForeground(_ scene: UIScene) {
        // Called as the scene transitions from the background to the foreground.
        // Use this method to undo the changes made on entering the background.
    }

    func sceneDidEnterBackground(_ scene: UIScene) {
        // Called as the scene transitions from the foreground to the background.
        // Use this method to save data, release shared resources, and store enough scene-specific state information
        // to restore the scene back to its current state.
    }
}

對(duì)于這個(gè)特性的適配

  • 方案 1:不需要多窗口(multiple windows)
    如果需要支持 iOS13 及之前多個(gè)版本的 iOS毡琉,并且又不需要多個(gè)窗口的功能,可以直接刪除以下內(nèi)容:
    1.info.plist文件中的Application Scene Manifest 的配置數(shù)據(jù)
    2.AppDelegate 中關(guān)于 Scene 的代理方法
    3.SceneDelegate 的類(lèi)
    4.實(shí)現(xiàn)UIApplicationDelegate的方法

如果使用純代碼來(lái)實(shí)現(xiàn)顯示界面妙色,需要在 AppDelegate中手動(dòng)添加 window 屬性:

class AppDelegate: UIResponder, UIApplicationDelegate {
    
    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        window = UIWindow(frame: UIScreen.main.bounds);
        window?.backgroundColor = .white
        window?.rootViewController = ViewController()
        window?.makeKeyAndVisible()
        
        return true
    }
}
  • 方案 2:需要多窗口
    不在 AppDelegate 的- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中初始化 window 了桅滋,因?yàn)?AppDelegate 中也沒(méi)有這個(gè)屬性了,轉(zhuǎn)交給 SceneDelegate 的 willConnectToSession: 方法進(jìn)行根控制器設(shè)置:
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
        
        guard let _ = (scene as? UIWindowScene) else { return }
        
        self.window = UIWindow(windowScene: scene as! UIWindowScene)
        self.window?.frame = UIScreen.main.bounds
        self.window?.backgroundColor = .white
        self.window?.rootViewController = ViewController1()
        self.window?.makeKeyAndVisible()
    }

下面是關(guān)于UIScene 以及 SceneDelegate 的一些介紹了身辨。

UIScene 的介紹

表示應(yīng)用程序用戶(hù)界面實(shí)例的對(duì)象丐谋。

描述:

  • 1.UIKit 為用戶(hù)或應(yīng)用程序請(qǐng)求的每個(gè)應(yīng)用的 UI 實(shí)例創(chuàng)建一個(gè)場(chǎng)景對(duì)象(也就是一個(gè) UIScene),也就是UIWindowScene(繼承于 UIScene) 對(duì)象煌珊。

  • 2.UIScene 會(huì)有一個(gè)代理對(duì)象(實(shí)現(xiàn) UISceneDelegate),用以接收 UIScene 的狀態(tài)改變号俐,例如,使用它來(lái)確定你的場(chǎng)景何時(shí)移動(dòng)到背景定庵。

  • 3.通過(guò)調(diào)用UIApplicationrequestSceneSessionActivation:userActivity:options:errorHandler:方法去創(chuàng)建一個(gè) scene吏饿。UIkit 還根據(jù)用戶(hù)交互創(chuàng)建場(chǎng)景踪危。

  • 請(qǐng)注意,我們使用的都是 UIWindowScene 找岖,而不是 UIScene陨倡。

方法列表
  • 創(chuàng)建一個(gè)實(shí)例
** 通過(guò)制定的UISceneSession對(duì)象和UIScene.ConnectionOptions創(chuàng)建一個(gè) UIScene**
** UISceneSession包含了一些配置信息**
public init(session: UISceneSession, connectionOptions: UIScene.ConnectionOptions)
  • 管理 Scene 的生命周期
** 實(shí)現(xiàn)UISceneDelegate方法的代理對(duì)象**
open var delegate: UISceneDelegate?
  • 獲取Scene屬性
** Scene的當(dāng)前執(zhí)行狀態(tài)。
** @available(iOS 13.0, *)
    public enum ActivationState : Int {
        case unattached  未連接到應(yīng)用程序的狀態(tài)许布。
        case foregroundActive 在前臺(tái)運(yùn)行
        case foregroundInactive 在前臺(tái)運(yùn)行正在接收事件
        case background 后臺(tái)運(yùn)行
    }
open var activationState: UIScene.ActivationState { get }

** Scene 的標(biāo)題兴革,系統(tǒng)會(huì)在應(yīng)用切換器中顯示這個(gè)字符串
open var title: String!
  • 指定場(chǎng)景的激活條件
** 使用這個(gè)屬性告訴UIKIt什么時(shí)候你想激活這個(gè)場(chǎng)景。
open var activationConditions: UISceneActivationConditions
  • 獲取和 Scene 相關(guān)的 session
** 只讀屬性蜜唾,UIKit為每個(gè)場(chǎng)景維護(hù)一個(gè)會(huì)話(huà)對(duì)象杂曲。session對(duì)象包含場(chǎng)景的唯一標(biāo)識(shí)符和關(guān)于其配置的其他信息。
open var session: UISceneSession { get }
  • 打開(kāi)URL
** 異步地加載指定的 URL,使用此方法打開(kāi)指定的資源袁余。如果指定的URL模式由另一個(gè)應(yīng)用程序處理擎勘,iOS將啟動(dòng)該應(yīng)用程序并將URL傳遞給它。啟動(dòng)應(yīng)用程序?qū)⒘硪粋€(gè)應(yīng)用程序帶到前臺(tái)颖榜。
open func open(_ url: URL, options: UIScene.OpenExternalURLOptions?, completionHandler completion: ((Bool) -> Void)? = nil)
  • 相關(guān)的通知
    @available(iOS 13.0, *)   UIKit向應(yīng)用添加了一個(gè)場(chǎng)景
    public class let willConnectNotification: NSNotification.Name

    @available(iOS 13.0, *)  UIKit 從應(yīng)用中移除了一個(gè)場(chǎng)景
    public class let didDisconnectNotification: NSNotification.Name

    @available(iOS 13.0, *)  指示場(chǎng)景現(xiàn)在在屏幕上棚饵,并相應(yīng)用戶(hù)事件
    public class let didActivateNotification: NSNotification.Name

    @available(iOS 13.0, *)  指示場(chǎng)景將退出活動(dòng)狀態(tài)并停止相應(yīng)用戶(hù)事件
    public class let willDeactivateNotification: NSNotification.Name

    @available(iOS 13.0, *)  場(chǎng)景即將開(kāi)始在前臺(tái)運(yùn)行
    public class let willEnterForegroundNotification: NSNotification.Name

    @available(iOS 13.0, *)  場(chǎng)景在后臺(tái)運(yùn)行
    public class let didEnterBackgroundNotification: NSNotification.Name

UISceneConnectionOptions

連接選項(xiàng)
描述:
UIKit 創(chuàng)建scene 有很多原因,它可以響應(yīng)切換請(qǐng)求或打開(kāi) URL 的請(qǐng)求掩完,當(dāng)有創(chuàng)建場(chǎng)景的特定原因時(shí)噪漾,UIKit 用關(guān)聯(lián)的數(shù)據(jù)填充 UISceneConnectionOptions 對(duì)象,并在連接時(shí)將其傳遞給代理且蓬,使用此對(duì)象中的信息進(jìn)行相應(yīng)的響應(yīng)欣硼。例如,如果是打開(kāi) UIKit 提供的 url恶阴,我們可以在場(chǎng)景中顯示他們的內(nèi)容诈胜。
不要直接創(chuàng)建UISceneConnectionOptions對(duì)象,UIKit 會(huì)自動(dòng)創(chuàng)建冯事,并將其傳遞給場(chǎng)景代理的scene:willConnectToSession:options:方法焦匈。

** 要打開(kāi)的url,以及指定如何打開(kāi)它們的元數(shù)據(jù)昵仅。
open var urlContexts: Set<UIOpenURLContext> { get }

** 發(fā)起請(qǐng)求的應(yīng)用程序的boundleID括授。
open var sourceApplication: String? { get }

** 掛起的切換活動(dòng)的類(lèi)型。
open var handoffUserActivityType: String? { get }

** 恢復(fù)場(chǎng)景的先前狀態(tài),用于將應(yīng)用還原到以前狀態(tài)的用戶(hù)活動(dòng)信息岩饼。
open var userActivities: Set<NSUserActivity> { get }

** 用戶(hù)對(duì)應(yīng)用程序通知之一的響應(yīng)荚虚。        
open var notificationResponse: UNNotificationResponse? { get }

** 處理快速動(dòng)作,用戶(hù)選擇要執(zhí)行的操作
open var shortcutItem: UIApplicationShortcutItem? { get }

** 有關(guān)應(yīng)用程序現(xiàn)在可用的CloudKit數(shù)據(jù)的信息。
open var cloudKitShareMetadata: CKShareMetadata? { get }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末籍茧,一起剝皮案震驚了整個(gè)濱河市版述,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌寞冯,老刑警劉巖渴析,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晚伙,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡俭茧,警方通過(guò)查閱死者的電腦和手機(jī)咆疗,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)母债,“玉大人午磁,你說(shuō)我怎么就攤上這事≌泵牵” “怎么了迅皇?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)衙熔。 經(jīng)常有香客問(wèn)我登颓,道長(zhǎng),這世上最難降的妖魔是什么红氯? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任框咙,我火速辦了婚禮,結(jié)果婚禮上痢甘,老公的妹妹穿的比我還像新娘扁耐。我一直安慰自己,他們只是感情好产阱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著块仆,像睡著了一般构蹬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上悔据,一...
    開(kāi)封第一講書(shū)人閱讀 49,850評(píng)論 1 290
  • 那天庄敛,我揣著相機(jī)與錄音,去河邊找鬼科汗。 笑死藻烤,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的头滔。 我是一名探鬼主播怖亭,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坤检!你這毒婦竟也來(lái)了兴猩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤早歇,失蹤者是張志新(化名)和其女友劉穎倾芝,沒(méi)想到半個(gè)月后讨勤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晨另,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年潭千,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片借尿。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡刨晴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出垛玻,到底是詐尸還是另有隱情割捅,我是刑警寧澤,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布帚桩,位于F島的核電站亿驾,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏账嚎。R本人自食惡果不足惜莫瞬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望郭蕉。 院中可真熱鬧疼邀,春花似錦、人聲如沸召锈。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)涨岁。三九已至拐袜,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間梢薪,已是汗流浹背蹬铺。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留秉撇,地道東北人甜攀。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像琐馆,于是被迫代替她去往敵國(guó)和親规阀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容