iOS13 项目中的SceneDelegate类有什么作用?自从Xcode11发布以来,当你使用新XCode创建一个新的iOS项目时,SceneDelegate会被默认创建,它到底有什么用呢。

在本文中,我们将深入探讨iOS 13和Xcode 11的一些变化。我们将重点关注SceneDelegate和AppDelegate,以及它们如何影响SwiftUI、Storyboard和基于XIB的UI项目。

通过阅读本文你将了解到:

  • SceneDelegate和AppDelegate的新变化
  • 他们是如何合作引导你的app启动的
  • 在纯手写App中使用SceneDelegate
  • 在Storyboards 和 SwiftUI项目中使用SceneDelegate

让我们开始吧。

本篇文章基于 Xcode 11 和 iOS 13.

AppDelegate

你可能对AppDelegate已经熟悉,他是iOS app的入口,application(_:didFinishLaunchingWithOptions:)是你的app启动后系统调用的第一个函数。

AppDelegate类实现了UIKit库中的UIApplicationDelegate 协议。而到了iOS13 AppDelegate的角色将会发生变化,后面我们会详细讨论。

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

  • 创建app的第一个view controller也就是 rootViewController
  • 配置并启动一些像日志记录和云服务之类的组件
  • 注册推送通知处理程序,并响应发送到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.boundswindow = UIWindow(frame: frame)window!.rootViewController = navigationwindow!.makeKeyAndVisible()return true
}

在上面的代码中,我们创建一个ViewController,并将其放在navigation controller中。然后将其分配给UIWindow对象的rootViewController属性。 这个window对象是AppDelegate的属性,它是我们的应用的一个窗口。

应用程序的window是一个重要的概念。 本质上,窗口就是应用程序,大多数iOS应用程序只有一个窗口。 它包含您应用的用户界面(UI),将事件调度到视图,并提供了一个主要背景层来显示您的应用内容。 从某种意义上说,“ Windows”的概念就是微软定义的窗口,而在iOS上,这个概念没有什么不同。 (谢谢,Xerox!)

好了,下面让我们继续SceneDelegate。

如果“窗口”的概念仍然不了解,请查看iPhone上的应用程序切换器。 双击Home键或从iPhone底部向上滑动,然后您会看到当前正在运行的应用程序的窗口。 这就是应用程序切换器。

The Scene Delegate

在iOS 13(及以后版本)上,SceneDelegate将负责AppDelegate的某些功能。 最重要的是,window(窗口)的概念已被scene(场景)的概念所代替。 一个应用程序可以具有不止一个场景,而一个场景现在可以作为您应用程序的用户界面和内容的载体(背景)。

尤其是一个具有多场景的App的概念很有趣,因为它使您可以在iOS和iPadOS上构建多窗口应用程序。 例如,文档编辑器App中的每个文本文档都可以有自己的场景。 用户还可以创建场景的副本,同时运行一个应用程序的多个实例(类似多开)。

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

  1. 现在,一个新的iOS项目会自动创建一个SceneDelegate类,其中包括我们熟悉的生命周期事件,例如active,resign和disconnect。
  2. AppDelegate类中多了两个与“scene sessions”相关的新方法:application(_:configurationForConnecting:options:)application(_:didDiscardSceneSessions:)
  3. Info.plist文件中提供了”Application Scene Manifest“配置项,用于配置App的场景,包括它们的场景配置名,delegate类名和storyboard

让我们一次开看一看。

1. Scene Delegate Class

首先,SceneDelegate类:

SceneDelegate的最重要的函数是:scene(_:willConnectTo:options:)。 在某种程度上,它与iOS 12上的 application(_:didFinishLaunchingWithOptions:) 函数的作用最相似。当将场景添加到app中时scene(_:willConnectTo:options:)函数会被调用的,因此这里是配置场景的最理想地方。 在上面的代码中,我们手动地设置了视图控制器堆栈,稍后会进行详细介绍。

这里需要特别注意的是,“SceneDelegate”采用了协议模式,并且这个delegate通常会响应任何场景。 您使用一个Delegate来配置App中的所有场景。

SceneDelegate 还具有下面这些函数:

  • sceneDidDisconnect(_:) 当场景与app断开连接是调用(注意,以后它可能被重新连接)
  • sceneDidBecomeActive(_:) 当用户开始与场景进行交互(例如从应用切换器中选择场景)时,会调用
  • sceneWillResignActive(_:) 当用户停止与场景交互(例如通过切换器切换到另一个场景)时调用
  • sceneWillEnterForeground(_:) 当场景变成活动窗口时调用,即从后台状态变成开始或恢复状态
  • sceneDidEnterBackground(_:) 当场景进入后台时调用,即该应用已最小化但仍存活在后台中

看到函数的对称性了吗? Active/inactive, background/foreground, 和 “disconnect”. 。 这些是任何应用程序的典型生命周期事件。

App Delegate中的Scene Sessions

在iOS13中AppDelegate中有两个管理Senen Session的代理函数。在您的应用创建scene(场景)后,“scene session”对象将跟踪与该场景相关的所有信息。

这两个函数是:

  • application(_:configurationForConnecting:options:), 会返回一个创建场景时需要的UISceneConfiguration对象

  • application(_:didDiscardSceneSessions:), 当用户通过“应用切换器”关闭一个或多个场景时会被调用

目前,SceneSession被用于指定场景,例如“外部显示” 或“ CarPlay” 。 它还可用于还原场景的状态,如果您想使用【状态还原】,SceneSession将非常有用。 状态还原允许您在应用启动之间保留并重新创建UI。 您还可以将用户信息存储到场景会话中,它是一个可以放入任何内容的字典。

application(_:didDiscardSceneSessions:)很简单。 当用户通过“应用程序切换器”关闭一个或多个场景时,即会调用该方法。 您可以在该函数中销毁场景所使用的资源,因为不会再需要它们。

了解application(_:didDiscardSceneSessions:)sceneDidDisconnect(_ :)的区别很重要,后者仅在场景断开连接时调用,不会被丢弃,它可能会重新连接。而application(_:didDiscardSceneSessions:)发生在使用【应用程序切换器】退出场景时。

3. Info.plist 中的Application Scene Manifest

您的应用支持的每个场景都需要在“Application Scene Manifest”(应用场景清单)中声明。 简而言之,清单列出了您的应用支持的每个场景。 大多数应用程序只有一个场景,但是您可以创建更多场景,例如用于响应推送通知或特定操作的特定场景。

Application Scene Manifest清单是Info.plist文件的一项,都知道该文件包含App的配置信息。 Info.plist包含诸如App的名称,版本,支持的设备方向以及现在支持的不同场景等配置。

请务必注意,您声明的是会话的“类型”,而不是会话实例。 您的应用程序可以支持一个场景,然后创建该场景的副本,来实现【多窗口】应用程序。

下面看一下的 Info.plist中清单的一些配置:

在红框内,您会看到Application Scene Manifest 这一条。 在它下面一条是Enable Multiple Windows,需要将其设置为“ YES”以支持多个窗口。 再往下Application Session Role的值是一个数组,用于在应用程序中声明场景。 你也可以在数组中添加一条【外部屏幕】的场景声明。

最重要的信息保存在Application Session Role数组中。 从中我们可以看到以下内容:

  • Configuration的名称,必须是唯一的
  • 场景的代理类名,通常为SceneDelegate
  • 场景用于创建初始UI的storyboard名称

Storyboard名称这一项可能使您想起Main Interface设置,该设置可以在Xcode 12项目的Project Properties配置中找到。 现在,在iOS应用中,你可以在此处设置或更改主Storyboard名称。

AppDelegate中的SceneDelegate、UISceneSession和Application Scene Manifest是如何一起创建多窗口应用的呢?

  • 首先,我们看SceneDelegate类。 它管理场景的生命周期,处理各种响应,诸如 sceneDidBecomeActive(_:) and sceneDidEnterBackground(_:)之类的事件。
  • 然后,我们再看看AppDelegate类中的新函数。 它管理场景会话(scene sessions),提供场景的配置数据,并响应用户丢弃场景的事件。
  • 最后,我们看了一下Application Scene Manifest。 它列出了您的应用程序支持的场景,并将它们连接到delegate类并初始化storyboard。

Awesome! Now that we’ve got a playing field, let’s find out how scenes affects building UIs in Xcode 11.

太棒了! 现在让我们了解scenes(场景)是如何影响Xcode 11中的用户界面的吧。

在SwiftUI中使用Scene Delegate

不久将来,SwiftUI将是创建iOS 13项目最简单的方法。 简言之,SwiftUI应用程序主要依靠SceneDelegate来设置应用程序的初始UI。

首先,SwiftUI项目中“Application Scene Manifest ”将长这样:

特别注意,配置中没有设置“Storyboard Name”这一项。 请记住,如果要支持多个窗口,则需要将Enable Multiple Windows设置为YES

我们将跳过“ 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 = windowwindow.makeKeyAndVisible()}}
}

上面的代码中发生了什么?

  • 首先,必须明确的是 在将新场景添加到应用中后 会调用scene(_:willConnectTo:options:)代理函数。 它提供了一个scene对象(和一个session)。 这个“UIWindowScene”对象是由应用创建的,您无需进行其他操作。
  • 其次,window属性会在这里用到。 App仍然使用“ UIWindow”对象,但现在它们已成为scene(场景)的一部分。 在if let代码块中,您可以清楚地看到如何使用scene来初始化UIWindow对象的。
  • 然后是设置window的rootViewController,将window实例分配给了场景的window属性,并且设置窗口makeKeyAndVisible为true,即将该窗口置于App的前面。
  • 接着为SwiftUI项目创建了ContentView实例,并通过使用UIHostingController将其添加为根视图控制器。 该控制器用于将基于SwiftUI的视图显示在屏幕上。
  • 最后但并非不重要的一点,值得注意的是,UIScene的实例化对象scene实际上是UIWindowScene类型的对象。 这就是as?对可选类型转换的原因。 (到目前为止,已创建的场景通常为“ UIWindowScene”类型,但我猜想将来还会看到更多类型的场景。)

所有这些看起来似乎很复杂,但是从高层次的概述来看,这很简单:

  • scene(_:willConnectTo:options:)被调用时,SceneDelegate会在正确的时间配置场景。
  • AppDelegate和Manifest的默认配置,他们没有涉及storyboard的任何东西。
  • scene(_:willConnectTo:options :)函数内,创建一个SwiftUI视图,将其放置在托管控制器中,然后将控制器分配给window属性的根视图控制器,并将该窗口放置在应用程序UI的前面 。

太棒了! 让我们继续。

您可以通过选择File(文件)→New(新建)→Project(项目)来建立一个基本的Xcode 11项目。 然后,选择Single View App, 在User Interface处选择SwiftUI来创建一个SwiftUI项目

在Storyboards项目中使用SceneDelegate

Storyboards和XIB是为iOS应用程序构建UI的有效方法。 在iOS 13上也是如此。 在将来,我们将看到更多的SwiftUI应用,但目前,Storyboards更常见。

有趣的是,即使有了SceneDelegate,通过Storyboards创建iOS项目你也不需要做任何额外的事情 只需选择File → New → Project。 然后,选择Single View App。 最后,为 User Interface 处选择 Storyboard ,就完成了。

设置方法如下:

  • 如我们前面提到过的,您可以在Info.plist中的“ Application Scene Manifest”中找到Main storyboard的设置地方。
  • 默认情况下,AppDelegate将使用默认的UISceneConfiguration。
  • SceneDelegate会设置一个“UIWindow”对象,并使用“Main.storyboard”来创建初始UI。

纯代码编写UI

许多开发人员喜欢手写UI,而随着SwiftUI的兴起,使用SwiftUI手写代码将会越来越常见。 如果您不使用storyboards,而使用XIB创建应用程序UI,该怎么办? 让我们看看SceneDelegate如何修改。

首先,AppDelegate和Application Scene Manifest中保持默认值。 我们不使用storyboard,所以需要在SceneDelegate类的scene(_:willConnectTo:options:)函数中设置初始视图控制器。

像下面这样:

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 = navigationself.window = windowwindow.makeKeyAndVisible()}}
}

上面代码很简单我们就不详细介绍了。

很简单,对吧? 使用SceneDelegate的核心是将一些代码从AppDelegate移至到SceneDelegate中,并正确配置 Application Scene Manifest 。

想要为现有的iOS项目添加scene(场景)支持? 可以查看Apple官方文档https://developer.apple.com/documentation/uikit/app_and_environment/scenes/specifying_the_scenes_your_app_supports。

作者:Reinder de Vries
翻译:乐Coding


更多Swift文章和iOS开发技术请关注公众账号:乐Coding。建了个【Swift开发】微信交流群,欢迎加入。

iOS13 Scene Delegate详解相关推荐

  1. Qt Quick 渲染之 Scene Graph 详解

    作者:billy 版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处 简介 在 Qt widget 中的渲染方式是传统的命令式绘图系统,使用 QPainter 依次为每个界面 ...

  2. C# delegate 详解

    delegate是C#中的一种类型,它实际上是一个能够持有对某个方法的引用的类. 与其它的类不同,delegate类能够拥有一个签名(signature),并且它只能持有与它的签名相匹配的方法的引用. ...

  3. delegate详解

    我们使用delegate关键字定义一个委托数据类型时,其实是定义了一个新类,此类派生自 MulticastDelegate,而 MulticastDelegate 又派生自 Delegate. 我们定 ...

  4. C#中delegate详解

    首先,delegate是什么?有过C语言或者C++基础的同学可以把他当做C语言和C#的函数的指针. 委托(Delegate)   是存有对某个方法的引用的一种引用类型变量.引用可在运行时被改变. 委托 ...

  5. Protocol与Delegate 使用方法详解

    你要知道的KVC.KVO.Delegate.Notification都在这里 转载请注明出处 http://blog.csdn.net/u014205968/article/details/78224 ...

  6. getinstance方法详解_二、设计模式总览及工厂模式详解

    二.架构师内功心法之设计模式 2.架构师内功心法之设计模式 2.1.课程目标 1.通过对本章内容的学习,了解设计模式的由来. 2.介绍设计模式能帮我们解决哪些问题. 3.剖析工厂模式的历史由来及应用场 ...

  7. webSocket详解

    前言 本文会用实例的方式,将iOS各种IM的方案都简单的实现一遍.并且提供一些选型.实现细节以及优化的建议. 注:文中的所有的代码示例,在github中都有demo: iOS即时通讯,从入门到&quo ...

  8. 《Unity 4 3D开发实战详解》一6.7 物理引擎综合案例

    本节书摘来异步社区<Unity 4 3D开发实战详解>一书中的第6章,第6.7节,作者: 吴亚峰 , 杜化美 , 张月霞 , 索依娜 责编: 张涛,更多章节内容可以访问云栖社区" ...

  9. 第 5 章 Nova - 041 - Resize Instance 操作详解

    Resize Instance 操作详解 Resize 的作用是调整 instance 的 vCPU.内存和磁盘资源. Instance 需要多少资源是定义在 flavor 中的,resize 操作是 ...

  10. 详解AI Lab 21篇CVPR 2018论文(附论文)

    来源:量子位 本文共8300字,建议阅读10分钟. 本文从立题背景.作者思路及研究特点为你详解计算机视觉顶会论文. 一年一度的计算机视觉顶会CVPR即将召开,入选论文也陆续揭晓. 今天分享入选论文解析 ...

最新文章

  1. [导入]还原精灵安装失败!
  2. EditText 编辑文本控件
  3. 安卓使用 HTTP 协议访问网络
  4. 关于文件描述符的问题的解决
  5. jQuery中的ready
  6. 铺磁砖,给定M*N的格子,用u*v的瓷砖去铺满,有多少种铺法
  7. 获取skipcase
  8. python实验九答案_Python程序设计实验报告:实验九 python 包管理
  9. matlab定积分如何使用,如何用matlab计算定积分.pdf
  10. Mac电脑网页完整的长截图怎么截
  11. element-ui在打开两个对话框时出现阴影的解决办法
  12. java 无锁并发_高并发情况下怎样尽量实现无锁编程
  13. 烦请大家支持一票,谢谢!!
  14. 什么是MTTF和MTBF和MTRF
  15. 天呐!350道Java面试真题分享
  16. 树莓派通过API向企业微信推送图文
  17. 适合mysql的网络存储_mysql 选择合适的存储引擎
  18. 坚持自主可控,长安链ChainMaker全面拥抱国密的技术实践
  19. ROS笔记(34) 工作空间规划
  20. VSCode远程开发 Resolver error: Error: Failed to install the VS Code Server

热门文章

  1. SYN包与SYN攻击原理
  2. 闪存flash进阶知识
  3. 【Python】接收UDP数据(保姆级图文+附测试工具文件+api例程)
  4. 华为网络设备-访问控制列表配置实验
  5. 吉林大学计算机学院杜天宇,2016年全国研究生数学建模竞赛获奖名单
  6. C语言中pow函数的使用
  7. CCKS2020基于本体的金融知识图谱自动化构建技术评测第五名方法总结
  8. 架构系列---QR二维码和扫描二维码登陆原理
  9. python绘制基因结构图_手把手教你从头绘制基因簇结构图
  10. C++ 异常是如何实现的