UIKit — 生命周期

在 iOS 13 及更高版本中,AppDelegateSceneDelegate 的连接并不是通过直接调用,而是通过配置和系统框架的机制来实现的。以下是它们如何协同工作的详细说明:

1. Info.plist 配置 #

Info.plist

在 iOS 13 及更高版本中,Info.plist 文件中有一个关键的配置项,UIApplicationSceneManifest,它定义了应用的场景支持。这是系统用来决定是否使用 SceneDelegate 的地方。

<key>UIApplicationSceneManifest</key>
<dict>
    <key>UIApplicationSupportsMultipleScenes</key>
    <true/>
    <key>UISceneConfigurations</key>
    <dict>
        <key>UIWindowSceneSessionRoleApplication</key>
        <array>
            <dict>
                <key>UISceneConfigurationName</key>
                <string>Default Configuration</string>
                <key>UISceneDelegateClassName</key>
                <string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
            </dict>
        </array>
    </dict>
</dict>
  • UISceneDelegateClassName: 这个键指定了场景的委托类,即 SceneDelegate。系统在需要创建一个新的场景时,会根据这个配置来实例化 SceneDelegate

2. 系统框架的机制 #

  • UIApplication: 当应用启动时,UIApplication 会根据 Info.plist 中的 UIApplicationSceneManifest 配置来决定是否使用场景支持。如果配置了场景支持,UIApplication 会自动管理 SceneDelegate 的生命周期。
  • UISceneSession: AppDelegate 中的 application(_:configurationForConnecting:options:) 方法返回一个 UISceneConfiguration,这个配置告诉系统使用哪个 SceneDelegate 来管理场景。

3. 代码执行流程 #

  1. 应用启动: 系统调用 AppDelegateapplication(_:didFinishLaunchingWithOptions:) 方法进行全局初始化。
  2. 场景创建: 如果 Info.plist 中配置了场景支持,系统会调用 AppDelegateapplication(_:configurationForConnecting:options:) 方法来获取场景配置。
  3. 场景连接: 根据场景配置,系统实例化 SceneDelegate,并调用其 scene(_:willConnectTo:options:) 方法来设置场景的 UI。

总结 #

AppDelegateSceneDelegate 的连接是通过 Info.plist 中的配置和系统框架的机制来实现的,而不是通过显式的代码调用。这种设计使得应用可以更好地支持多任务和多窗口环境。

细节需要继续参考 #

UISceneDelegate

https://developer.apple.com/documentation/uikit/uiscenedelegate#

Specifying the scenes your app supports

https://developer.apple.com/documentation/uikit/specifying-the-scenes-your-app-supports

示例项目:

https://github.com/shankarmadeshvaran/SwiftUI_Tasks

配置如下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>LSRequiresIPhoneOS</key>
	<true/>
	<key>UIApplicationSceneManifest</key>
	<dict>
		<key>UIApplicationSupportsMultipleScenes</key>
		<false/>
		<key>UISceneConfigurations</key>
		<dict>
			<key>UIWindowSceneSessionRoleApplication</key>
			<array>
				<dict>
					<key>UISceneConfigurationName</key>
					<string>Default Configuration</string>
					<key>UISceneDelegateClassName</key>
					<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
				</dict>
			</array>
		</dict>
	</dict>
	<key>UILaunchStoryboardName</key>
	<string>LaunchScreen</string>
	<key>UIRequiredDeviceCapabilities</key>
	<array>
		<string>armv7</string>
	</array>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
	</array>
	<key>UISupportedInterfaceOrientations~ipad</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
		<string>UIInterfaceOrientationLandscapeLeft</string>
		<string>UIInterfaceOrientationLandscapeRight</string>
	</array>
</dict>
</plist>

配置在 Info.plist 的原因 #

在 iOS 13 及更高版本中,多窗口支持与 SceneDelegate 密切相关,但并不是每个窗口都有一个独立的 SceneDelegate 类。相反,SceneDelegate 类的实例是与每个窗口(或场景)相关联的。以下是它们之间的关系和工作机制:

多窗口与 SceneDelegate 的关系 #

  1. 场景(Scene):
  • 在 iOS 中,场景代表应用的一个实例或用户界面。每个场景可以对应一个窗口,尤其是在 iPad 上支持多窗口的情况下。
  1. SceneDelegate 实例:
  • 每个场景都有一个对应的 SceneDelegate 实例。SceneDelegate 负责管理该场景的生命周期事件,如进入前台、进入后台、断开连接等。
  1. 共享 SceneDelegate 类:
  • 虽然每个场景有一个 SceneDelegate 实例,但它们通常共享同一个 SceneDelegate 类。也就是说,开发者只需定义一个 SceneDelegate 类,系统会为每个场景创建该类的一个实例。

工作机制 #

  • 场景配置:

  • Info.plist 中,通过 UIApplicationSceneManifest 配置场景支持。UISceneConfiguration 指定了 SceneDelegate 类。

  • 场景创建:

  • 当用户在 iPad 上打开应用的一个新窗口时,系统会创建一个新的场景,并实例化一个 SceneDelegate

  • 场景管理:

  • SceneDelegate 的每个实例管理其对应场景的生命周期事件。开发者可以在这些事件中执行特定的逻辑,如保存数据、更新 UI 等。

代码示例 #

假设你有一个 SceneDelegate 类:

class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // 初始化窗口和根视图
    }

    func sceneDidBecomeActive(_ scene: UIScene) {
        // 场景变为活跃状态
    }

    func sceneWillResignActive(_ scene: UIScene) {
        // 场景将进入非活跃状态
    }
}

当用户在 iPad 上打开应用的多个窗口时,系统会为每个窗口创建一个 SceneDelegate 实例。每个实例独立管理其窗口的生命周期。

总结 #

  • 一个 SceneDelegate : 通常只需要一个 SceneDelegate 类。
  • 多个 SceneDelegate 实例: 每个窗口(场景)有一个 SceneDelegate 实例。
  • 独立管理: 每个实例独立管理其对应场景的生命周期。

这种设计使得应用可以更好地支持多任务和多窗口环境,提供更灵活和强大的用户体验。

本文共 1355 字,上次修改于 Jan 4, 2025