作者:Damien,iOS 开发者。目前就职于携程。
Session: developer.apple.com/videos/play…
前言
通过此 Session 你将学习如何在 SwiftUI 中构建文档型 App, 通过 DocumentGroup API,以及 Pure SwiftUI App 和 Scenes 组合,使你的 App 对文档管理的快速集成,例如文档浏览和 iCloud 文件浏览,而无需繁琐多余的工作。
概述
对于用户而言,访问和处理文档是最常用的操作。文档型 App 的功能也很明确:
- 可以创建文档和打开文档
- 用户可以编辑文档并将其保存到磁盘
- 可以分享文件给另一个用户
- 管理磁盘上的文件
- 可以针对 iCloud 文件做增删查改操作
文字或许比较抽象,我们列举几个比较知名的 App 以便你快速理解什么是文档型 App
- iOS / iPadOS 中的文件应用
- Xcode & 系统邮件 App
- 写作软件 Ulysses & 思维导图软件 MindNode
等等...
早在 2017 年的 iOS 11 中,Apple 就发布了 Session 来讲述如何在 iOS 中构建文档型 App,具体可以查看 Session(Building Great Document-based Apps in iOS 11)。
然而在现在 (iOS 14) ,Apple 把它带到了 SwiftUI 中,并且提供了更简单、更优雅的方式让开发者接入,接下去,我们会带你一步步深入如何使用 SwiftUI 去开发一个文档型 App,最终我们会完成一个提供绘图并且具有保存绘图数据,打开绘图文件的功能 Mac / iPadOS 应用。
原理探索
创建项目
使用 Xcode 12 创建一个 Document App。我们这边可以选择多平台。因为我们要支持 iPadOS 和 MacOS
代码初探
创建成功后,你可以看到 Xcode 生成的模板代码结构
@main
struct TextEdit: App {
var body: some Scene {
DocumentGroup(newDocument: TextDocument()) { file in
TextEditor(text: file.$document.text)
}
}
}
可以注意到,在 iOS 14 中,SwiftUI 代码发生了一些变化,如之前的 some View
变成了 some Scene
,同时也多出了 App
& DocumentGroup
这 2 个新东西。
别急,我会带你们一步步深入探索其中的变化。
首先,我们来看一张层级图:
App: SwiftUI 的新 API,App protocl 使我们能够轻松地用一个结构来替换 AppDelegate 和 SceneDelegate,该结构将管理我们的场景和应用生命周期。
Scene: SwiftUI 的新 API,它表示界面可以由不同的平台独立显示。
DocumentGroup: SwiftUI 的新 API,它可以自动管理 iOS,iPadOS 和 macOS 支持的,基于文档的场景的打开,编辑和保存。
在不同平台下 DocumentGroup
的表现为:
- iPadOS:
- MacOS:
想了解更多 SwiftUI 的变化可以查看:WWDC 2020 - What's new in SwiftUI
好了,了解了这些概念之后,我们可以成功运行下 App (MacOS),看看效果
嗯,是一个具备基本能力的简易编辑器
让我们梳理下内部代码流程方便理解:
1、 App 文件中,使用了我们的新的 API App
& @main
指定了程序的入口,最外层使用新 API Scene
以便界面可以由不同的平台独立显示,并且使用了我们的新 API DocumentGroup
自动管理文档的场景的打开,编辑和保存,之后初始化了 ContentView
来进行 UI 展示
2、 在 ContentView
中, ContentView_Previews
不用关心,这是 SwiftUI 预览的入口,不是我们关心的重点,回过头看,ContentView
中,我们使用了 TextEditor(Swift iOS 14 新控件)
来展示了文档的文本,也就是之前我们 Demo 中的 Hello world 部分的 UI。
3、 ShapeEditDocument
实现了协议FileDocument
,来完成写入和打开文件的一系列操作。
FileDocument:FileDocument
是 iOS 14 中也是新增的 API。FileDocument
协议是用于在文件内容之间进行序列化的文档模型定义。需要实现以下几个方法:
init(fileWrapper: FileWrapper, contentType: UTType)
在遵守FileDocument
协议的对象被创建的时候,会被回调,可能是初始化,也有可能是打开某个文件时创建新的对象。func write(to: inout FileWrapper, contentType: UTType)
需要被保存到磁盘的时候会被回调。var readableContentTypes: [UTType]
返回可以识别 UTType。
UTType 是个什么呢?
UTType(Uniform Type) :是唯一标识抽象类型的字符串。它们可以被用来描述文件格式或内存中的数据类型,但也可以被用来描述其它种类实体的类型,比如目录、用量或包。
更进一步
上文我们实现了一个简单的文本编辑器,接下去,我们要完成一个自定义绘图软件。并完成保存和加载自定义文件格式的功能。我们来做一些改造:
1、 重构ShapeEditDocument
的代码,使其支持我们自定义的格式来保存,我们这边使用 JSON 编码和解码来序列化我们的图形信息。
代码修改如下:
代码详解
我们修改了init(fileWrapper: FileWrapper, contentType: UTType)
和func write(to: inout FileWrapper, contentType: UTType)
方法。在加载的方法中使用 JSON 解码,在写入磁盘的方法中我们使用了 JSON 编码。
2、 向系统注册自定义扩展类型
系统会维护一个列表,包含哪些类型的文件可以由哪些 App 去处理,我们需要实现自定义类型的加载和保存,所以我们需要向系统去注册我们可以处理哪些类型的文件。 修改如下:
代码详解
我们扩展了 UTType,自定义的 UTType:com.example.ShapeEdit.shapes
。
之后重写var readableContentTypes: [UTType]
,使其返回了自定义类型。
注意:
UTType 有 ExportedType & ImportedType 之分。前者代表着我们的 App 拥有的专用类型向系统注册,后者标识是其他 App 拥有的类型,但是我们可以支持使用。 更多细节可以查看文档:
Defining File and Data Types for Your App
3、最后,将我们的 TextEditor
替换为我们自定义绘图的Canvas
对象即可(由于篇幅问题,展示不放出代码细节)
至此,我们的今天的 Session 的探索之路完美结束。
总结
在 iOS 14 中,Apple 给我们带来了更简洁的方式去创建文档型 App,区区几行代码即可实现功能强大的文档操作 App。希望开发者能基于此创造更大的价值。
推荐阅读
WWDC20 10041 - What's new in SwiftUI
WWDC20 10048 - 在 SwiftUI 中创建复杂功能
限时福利
这篇文章的内容来自于 《WWDC20 内参》。在这里给大家推荐一下这个专栏。
「WWDC 内参」系列是由老司机周报、知识小集合以及 SwiftGG 几个技术组织发起的。已经做了几年了,口碑一直不错。主要是针对每年的 WWDC 的内容,做一次精选,并号召一群一线互联网的 iOS 开发者,结合自己的实际开发经验、苹果文档和视频内容做二次创作。
今年一共有 213 个 Session 的内容。《WWDC20 内参》挑选了其中的 135 个 Session,专栏现已创作了 97 篇文章。目前正在优惠销售,只需要 29.9 元,十分优惠。
看了文章还不过瘾的朋友,抓紧订阅 《WWDC20 内参》 https://xiaozhuanlan.com/wwdc20 继续阅读吧~
关注我们
我们开通了公众号「老司机技术周报」,每期发布时公众号(LSJCoiding)会推送消息,欢迎关注。