如果将Xcode更新到11, 创建项目。默认会创建SceneDelegate.swift, 那么问题来了, 这个代理用来干嘛的了?

在这篇文章中,我们将探索iOS13和Xcode11的改变。我们着重介绍scene和Delegates , 看看他们事如何影响SwiftUI,Storyboard和Xib构建的UI.

我们将学习到:

  • AppDelegate和SceneDelegate
  • 程序启动时,他们如何一起工作的
  • 怎么设置app的scene deleagate
  • 在Storyboard和SwiftUI不同环境中如何使用scene delegate

系好安全带,发车。。。

这篇文档项目环境Xcode11 和 iOS13

AppDelegate

我们对于AppDelegate非常熟悉,他是一个App启动的入口,其中的 application(_:didFinishLaunchingWithOptins: ) 方法是系统操作唤醒的第一个方法。

AppDelegate 遵守UIKit框架的UIApplicationDeleaget ,但是在iOS13中app delegate发生了改变 ,我们能很快发现。

以下是iOS12 app deleget 的常规操作:

  • 设置第一个ViewController,我们叫做它root View Controller吧
  • 配置app设置和启动模块,比如登录,连接服务器等
  • 注册推送通知回调,响应发送到app的推送通知
  • 响应app生命周期事件,比如进入后台,唤醒和退出应用

使用Storyboard启动的app, app delegate都是千篇一律的。因为它只返回true 就像下面这个方法:

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

一个简单的使用Xib的app, 需要设置自己的根控制器,就像这样:

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
}

在上面的代码中,我们创建了一个控制器, 并且把他放在导航栏控制器中,把他分配为给 UIWindow对象的rootController属性。 这个window对象是 app delegate的属性, 是我们app拥有的一个window.

app的window是iOS中一个非常重要的概念, 一般一个window就是一个app,而且大部分iOS 应用只有一个window, 它就是你应用 UI界面的可视, 用户点击事件, 提供后台显示内容。 当然这里的window和微软的Windows不是一个东西, 是不同的概念(谢谢你 Xerox!)。

好现在我们把重点放在scene delegate。

SceneDelegate

在iOS 13及以上 scene delegate 将扮演 一些 app delegate 的作用, 大多数情况窗口(window)的概念被场景(scene)替换。 一个应用可以有多个场景, 而场景又是作为应用的界面和内容的呈放。

一个app有多个场景的概念来说是特别地, 而且这样就允许您创建多窗口的iOS或者iPadOS应用。在一个 文本处理app中,每一个文档都可以有自己的场景。例如, 用户可以创建一个场景的复制场景, 一次可以运行一个app的多实例。

在Xcode 11中跳转使用scene delegate有三个地方:

  1. 新建一个项目,会自动创建SceneDelegate 类, 它包括 生命周期事件,比如 动作, 注册, 连接等
  2. AppDelegate中有两个关联scene sessions的方法,叫做 application(_:configurationForConnecting: options:) 和 application(_: didDiscardSceneSessions:)
  3. 在 Info.plist文件中的属性列表中有一个Application Scene Manifests(应用场景清单)属性(如下图),可以进行相应配置, 比如类、代理、 storyboard名字等

好,让我们一步一步操作。

1. 场景代理类(Scene Delegate Class)

SceneDelegate类如:

import UIKitclass 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.}}

场景代理中最重要的方法是 scene(_:willConnectTo:options:), 一般来说它等同于iOS 13之前的 application(_: didFinishLaunchingWithOptions:)方法, 场景被添加到app,这个方法将被调用, 这是配置场景完美的地方。 在上面的代码中, 我们可以设置controller栈,这个设置我们等会儿再说

重点注意SceneDelegate在使用delegate时,当然 一个delegate 也可以响应任何场景,如果你想使用一个代理配置所有场景的话。

SceneDelegate也包含下面这些方法:

  • sceneDidDisConnect(_:) 场景没有连接时调用(等一会儿他会再连接)
  • sceneDidBecomeActive(_:) 当用户开始进入场景时调用,比如从app switcher(应用切换)选中app
  • scenewillResignActive(_:) 当用户停止进入场景,比如进入另一个场景
  • sceneWillEnterForeground(_:) 当用户将要进入前台,比如从后台开始或者唤醒
  • sceneDidEnterBackground(_:) 当场景将要进入后台,比如 app 最小化,但是依然在后台运行

2. 应用代理:场景会话(AppDelegate : Scene Sessions)

在iOS13中, Appdelegate类现在包含了与secene sessions 相关的方法。 创建一个场景的同是 场景对象也会随之创建,场景会话对象跟踪管理场景的相关信息, 方法如下:

  • application(_: configurationForConnecting: optings:) 这个是返回场景配置对象的。
  • application(_:didDiscardSceneSessions:) 你的app用户关闭一个或者多个场景时调用。

现在, 场景会话用于指定一个场景, 比如 "External Display" 或者 "CardPlay", 也被用来存储一个场景的状态, 用于状态恢复非常好用。 状态恢复允许你恢复或者再次创建UI在app启动期间。你也可以分配用户信息到场景会话中, 这是一个你可以放入任何能放入的字典。

application(_:didDiscardSceneSession:) 是非常简单的, 当用户通过应用切换来关闭一个或者多个场景时会调用。你可以在这里释放一些你场景使用的资源,因为他们不在需要使用了。

对比与 sceneDidDisconnect(_:) , 这个方法标识当场景仅仅失去连接,但是不一定丢弃。 它可能会尝试重连, 直到application(_:didDiscardSceneSession:) 使用应用切换标记场景退出。

3.Info.plist中的应用场景清单(Application Scene Manifest)

你使用的每一个场景都需要在应用场景清单中声明过, 简而言之就是清单列出你应用支持的场景。 大多是app只有一个场景,但是你能创建更多个,比如响应通知或者事件的单独场景。

应用场景清单也是Info.plist文件中的一部分,Info.plist也是一个明确知道应用配置的好地方。该文件属性列表包含应用名字,版本号,支持设备方向等

注意在这里声明session的类型, 而不是session本身。 你的app能支持一个场景, 创建一个场景的副本和使用它来创建多窗口app.

以下是Info.plist的列表大概:

在顶层,你可以看见应用场景清单子项,下面时Enable Multiple Windows ,如果你需要支持多窗口,需要设置为YES. 再往下是一个声明应用内场景的Applicaiton Session Role数组。 另一个部分能用于声明外部场景。

最重要的信息是Application Session Role 数组部分, 包括:

  • Configeration Name 配置的名字,必备的
  • 场景的类名, UIWindowScene
  • Delegate Class Name 场景代理类名,一般是SceneDelegate
  • 场景初始化storyboard的名字

storyboard的名字部分主要提醒用户主Storyboard,以便于在Xcode 12 的项目属性配置中看到。 一般基本iOS 应用中, 如果你不使用场景这就是你设置或改变主要Storyboard的地方【译者发现,如果需要改变主显示Storyboard,只能在这里修改,直接在项目的General -> Deployment Info -> Main Interface中修改是没有效果的。 】。

如何用SceneDelegate、 AppDelegate中的scene session 应用场景清单怎么创建多窗口app?

  • 首先,我们已经了解过Scenedelegate类, 它管理场景的声明周期,响应事件(比如sceneDidBecomeActive(_:)和 sceneDidEnterBackground(_:))
  • 之后,我们检查Appdelegate的新方法,它管理场景会话,提供场景配置数据, 用户丢弃场景响应
  • 最后,我们查看应用场景清单(Application Scene Manifest),它罗列出你应用支持的场景, 代理类和初始化storyboard

太棒了!有了初步了解,我们看看用Xcode11创建UI,看看是如何影响的。

基于SwiftUI的Scene Delegate

iOS13最简单创建项目方法是使用SwiftUI, 简单来说  SwfitUI创建的项目大多是都是通过SceneDelegate设置初始化UI的

首先看看SwiftUI的应用场景清单长什么样子:

这是非常标准的,对于默认app,哪里标准了? 使用Default Configuration标识不包含的Storyboard Name Set 。记住, 如果你想支持多窗口,需要吧Enable Multiple Windows 设置为 YES.

我们跳过AppDelegate, 因为它非常标准,只返回true.

下一步, 看看 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(_:willConnetectTo:options:)协议方法(当一个新场景加入),提供scene对象和session, 这个UIWindowScene对象是app创建的,如此一来你就不需要手动创建。

之后,这个window属性被使用,应用仍然有UIWindow的window对象,只不过现在他们是场景的一部分。在代码中,在if let 闭包内,你可以清楚的看见使用scene参数初始化的UIWindow实例。

设置window的rootViewController属性,然后这个window变为可见(make key add visible),目的是把它放在UI层的最前面。

使用SwiftUI,你要注意,被创建的ContentView作为root view controller 通过使用UIHostingController, 这个控制器把SwiftUI基本视图放在屏幕上。

方法中有一点注意,类型为UIScene的scene参数,实际上UIWindowScene类型的实例。使用as 可选解析(到目前为止,创建的场景通常是UIWindowScene类型,但我猜想在未来,我们会看到更多类型的场景。)

所有的看起来很复杂,但是总体来看非常简单。

  • scene delegate 中配置场景,合适的时间,就是当scene(_:willConnectTo:options:) 被调用时。
  • app delegate 和Manifest ,有默认的配置,不需要引入storyboard
  • scene(_:willConnectTo:options:)方法中创建SwiftUI的视图, 放在hosting controller中,分配它为window属性的root view controller,把他们设置为UI层最前端就好了。

非常棒!让我们开始

你可以使用Xcode11创建基本项目, 选择SwfitUI, 通过选择File -> New -> Project, 之后选择 Single View App, 最后选择 SwiftUI作为User Interface

基于Storyboard的SceneDelegate

Storyboards, XIBs, 是创建UI的有效的方式。 但是在iOS 13上是一样的。在以后,我们会看到越来越多SwiftUI 应用, 但是现在, storyboard更常用。

有趣的是,你无法多余操作,只需要选择File-> New -> Project, 选择Single View App, 最后选择 Storyboard作为User Interface , 就完成了。

下面使步骤:

  • 就像之前所述,在Info.plist,你发现Main storyboard 在 Application Scene Manifest的字典中
  • 默认app delegate将使用默认的场景配置
  • 默认scene delegate  设置 UIWindow对像,使用Main.storyboard创建初始化UI

设置你应用的编程方式

很开发者使用代码创建UI, 随着SwiftUI的崛起, 我们能看到更多。 那如果你不是用Storyboard,而是使用xib来创建你得app UI , 来看看场景代理如何适配它吧。

首先, app delegate 和 Applicaton 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()}}

我们来看看发生了啥:

  • 就像之前,我们持有UIWindow类型的window属性,它是用windowScene对象初始化的,该对象是由scene参数进行类型转换的
  • 在 if le闭包内, 就像上面的代码, 这就是在iOS 12及之前设置根控制器的方式在AppDelegate, 你厨师化一个view controller, 把他放在导航栏控制器里, 设置给rootViewController
  • 最后,window常量分配给window属性, 然后让它可见,把他放在屏幕最前面。

很简单,对吧? 最核心的是,把你之前在app delegate中代码移到scene delegate ,配置Applicaton Scene Manifest

还在找怎么为已存在的项目添加场景支持吗? 看这个吧

深入学习

完美了!这只是示例的一小部分, 随着我们的深入,场景代理允许你添加多窗口应用

你可能已经学会怎样为SwiftUI、Storyboard设置场景代理, 我们也看了使场景工作的三部分:app delegate , scene delegate , Application Scene Manifest , 非常棒!

想要学习更多吗? 通过下面资源学习吧:

  • Getting Started With SwiftUI
  • View Controllers Explained: Ultimate Guide For iOS & Swift
  • What’s New In Swift 5.0
  • How To: Working With Plist In Swift
  • How To Keep Up With Swift Changes

iOS 13 Xcode11 中的 Scene Delegate相关推荐

  1. iOS 13 Scene Delegate and multiple windows

    iOS 13 Scene Delegate and multiple windows iOS 13的一大改进就是支持multiple windows(多窗口)功能,虽然多窗口仅在iPadOS上获得支持 ...

  2. iOS 13 问题解决以及苹果登录,暗黑模式

    本文对应github地址iOS 13 问题解决以及苹果登录,如果由于github调整导致资源找不到或细节更改,请访问github 本文掘金地址 本文直接搬砖,随便看看就行 iOS 13 (Xcode1 ...

  3. ios 自己创建的动态frameworks 怎么发布_iPadOS/iOS 13.1 正式发布,这才是真正的 iOS 13 系统...

    点击上方蓝色字体,关注我们    苹果发布 iPadOS / iOS 13.1 ,你装13了吗? 在 iOS 13 系统发布数日之后,苹果今晨如约提前发布了该系统的首个重要更新--iOS 13.1,补 ...

  4. iPad连android热点掉线,苹果终于承认,iOS 13有这个问题,网络断连的原因找到了...

    原标题:苹果终于承认,iOS 13有这个问题,网络断连的原因找到了 3 月 21 日,据 MacRumors 报道,Apple 于近期向授权服务提供商发布内部文档,承认部分升级至 iOS / iPad ...

  5. iOS 13新增防骚扰功能,但开启后用户吐槽声一片

    不知道已经用上iOS 13的用户们,有没有发现新系统中已经加入了电话防骚扰功能? 据国外媒体报道,按照苹果最新的讲述来看,苹果在iOS 13系统中加入了新的功能,而这个功能颇为实用,可以帮助用户对抗骚 ...

  6. ios 扫码枪外设 键盘模式_苹果iOS 13新增滑行键入功能 开启新键盘模式

    滑行输入又称扫屏输入,是近年触摸屏幕/触摸键盘上流行的输入技术,它的特点是:你只需要在要录入单词的几个字母之间滑行,系统词库就能把你需要的单词给找出来,无需考虑顺序.排列.冗余甚至无需考虑多输入进去的 ...

  7. 关闭切换大小写提示_你不知道的iOS 13提示和技巧

    iOS 13充满了我们过去几年一直在询问的新功能和变化.在黑暗的模式终于在这里,提醒应用程序要好得多,快捷键的应用程序现在有真正的自动化,Safari浏览器得到一个下载管理器和文件应用最后用外部存储工 ...

  8. 安卓桌面整理app_升级到 iOS 13,你还会删除 APP 和整理桌面了吗?

    苹果已经正式发布了 iOS 13系统,在 iOS 13系统中,苹果带来了大量的新功能和改进,其中包括取消了原来桌面3D Touch 的操作方式,改为不再感应压力,通过长按图标模拟之前的压感,呼出3D ...

  9. 苹果工具条_苹果iOS 13.4大版本更新正式推送!新功能+新表情登场

    近日,苹果发布了iOS 13.4的第二个公测版本,与之前版本相比,此次的新版本增添了不少的亮眼功能,同时在设计方面也有所更改并且修复了一些bug. 话不多说,看一下iOS 13.4有没有你期待的变化与 ...

最新文章

  1. 【Axure原型图】—— 4. Tab Control(选项卡)
  2. java 反射 hold_Go进阶:反射3定律
  3. 结巴分词关键词相似度_辨别标题党--提取关键词与比较相似度
  4. NET 连接池救生员
  5. 1万字说清楚Receiver Operating curve(ROC) 受试者操作特征曲线
  6. Java-简易加法计算器代码优化
  7. Python 数据框将某列设置为新索引、重新定义行索引、及获取列名
  8. 架构搜索文献笔记(5):《APQ:联合搜索网络结构、剪枝和量化策略》
  9. 计算机技能比赛培训总结怎么写,技能大赛总结范文
  10. 使用Blinker+ESP8266接入天猫精灵
  11. PHP防红接口,域名防红php源代码
  12. 大学综合测评中,使用VBA代码自动完成EXCEL成绩表
  13. Vue超全资源,收藏!
  14. 入门视频采集与处理(BT656简介)
  15. Unity Serialize总结
  16. 科普篇|工厂里常说的QC, IQC, IPQC, QA 是什么
  17. ColorSchemer Studio 2 (专业配色软件) 中文破解版
  18. Linux查询服务器保修信息
  19. html生成报告,生成HTML测试报告
  20. SymmetricDS 数据库双向同步开源软件入门

热门文章

  1. jsp弹窗修改信息_WEB最最最初级修改用户信息
  2. bzoj3171: [Tjoi2013]循环格(费用流)
  3. x-manager 管理 kvm虚拟机
  4. array_map与array_column之间的关系
  5. 上传Android或Java库到Maven central repository(转载)
  6. “口碑营销”产品模型推测与分析
  7. appium ios 真机自动化环境搭建
  8. sql的nvl()函数
  9. HDU 2534 Score
  10. Qt irrlicht(鬼火)3D引擎 摄像机旋转问题