iOS13新特性 - SceneDelegate

SceneDelegate是為了支持 iOS13之后的 iPadOS 多窗口口而退出的。Xcode11 默認會創(chuàng)建通過 UIScene 管理多個 UIWindow 的應(yīng)用,工程中除了 AppDelegate 外會多一個 SceneDelegate。并且 AppDelegate.h 不再有 window 屬性,window 屬性被定義在了 SceneDelegate.h 中,SceneDelegate 負責原 AppDelegate 的 UI 生命周期部分的職責。

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


    image.png

這種模式完全沒有問題,因為只有一個進程,只有一個與這個進程對應(yīng)的用戶界面。

  • iOS13 之后
    AppDelegate 的職責是處理 App 的生命周期;
    新增的 SceneDelegate 是處理 UI 的生命周期。
image.png
image.png
  • Xcode11 新建項目的 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 新建項目的 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.
    }
}

對于這個特性的適配

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

如果使用純代碼來實現(xiàn)顯示界面,需要在 AppDelegate中手動添加 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 了,因為 AppDelegate 中也沒有這個屬性了,轉(zhuǎn)交給 SceneDelegate 的 willConnectToSession: 方法進行根控制器設(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)用程序用戶界面實例的對象。

描述:

  • 1.UIKit 為用戶或應(yīng)用程序請求的每個應(yīng)用的 UI 實例創(chuàng)建一個場景對象(也就是一個 UIScene),也就是UIWindowScene(繼承于 UIScene) 對象。

  • 2.UIScene 會有一個代理對象(實現(xiàn) UISceneDelegate),用以接收 UIScene 的狀態(tài)改變,例如,使用它來確定你的場景何時移動到背景。

  • 3.通過調(diào)用UIApplicationrequestSceneSessionActivation:userActivity:options:errorHandler:方法去創(chuàng)建一個 scene。UIkit 還根據(jù)用戶交互創(chuàng)建場景。

  • 請注意,我們使用的都是 UIWindowScene ,而不是 UIScene。

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

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

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

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

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

    @available(iOS 13.0, *)  場景即將開始在前臺運行
    public class let willEnterForegroundNotification: NSNotification.Name

    @available(iOS 13.0, *)  場景在后臺運行
    public class let didEnterBackgroundNotification: NSNotification.Name

UISceneConnectionOptions

連接選項
描述:
UIKit 創(chuàng)建scene 有很多原因,它可以響應(yīng)切換請求或打開 URL 的請求,當有創(chuàng)建場景的特定原因時,UIKit 用關(guān)聯(lián)的數(shù)據(jù)填充 UISceneConnectionOptions 對象,并在連接時將其傳遞給代理,使用此對象中的信息進行相應(yīng)的響應(yīng)。例如,如果是打開 UIKit 提供的 url,我們可以在場景中顯示他們的內(nèi)容。
不要直接創(chuàng)建UISceneConnectionOptions對象,UIKit 會自動創(chuàng)建,并將其傳遞給場景代理的scene:willConnectToSession:options:方法。

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

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

** 掛起的切換活動的類型。
open var handoffUserActivityType: String? { get }

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

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

** 處理快速動作,用戶選擇要執(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)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容