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 的生命周期脓匿。
這種模式完全沒(méi)有問(wèn)題,因?yàn)橹挥幸粋€(gè)進(jìn)程宦赠,只有一個(gè)與這個(gè)進(jìn)程對(duì)應(yīng)的用戶(hù)界面陪毡。
- iOS13 之后
AppDelegate 的職責(zé)是處理 App 的生命周期;
新增的 SceneDelegate 是處理 UI 的生命周期勾扭。
- 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)用
UIApplication
的requestSceneSessionActivation: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 }