大多数浏览器和
Developer App 均支持流媒体播放。
-
UI Data Sources 改进
通过 UI Data Sources ,您可以利用自动比较功能轻松地更新表格视图和集合视图项目。自动实现高保真、高质量的素材组变更动画,无需额外的代码!这种改进的数据源机制可以彻底避免同步错误、异常和崩溃!了解这种用于标识符和快照的简化数据模型,以便您可以将精力集中到 app 的动态数据和内容上,而非 UI 数据同步这样的琐事。
资源
相关视频
WWDC20
WWDC19
-
下载
欢迎
我是 Steve Breen 我是 UIKit 团队的一名工程师 今天我和我的同事 来自 AppKit 团队的 Troy Stephens 和来自 App Store 团队的 Jacob Klapper 一起
今天我们要聊一些 关于 UI 数据源的内容 那么 今天的演讲将分为四个部分 首先我想谈谈 目前的最新状况 我们现在如何 在平台上与数据源交互
然后我们将讨论 一种全新的方法 将其引入 iOS tvOS 和 macOS 接下来我们会过渡到一些演示 获得一些关于这个 全新 API 的实践 最后我们将 更详细地考虑 如何充分利用 这个新 API 我们来谈谈 目前最新的状况 我们是如何在 UITableView 和 UICollectionView 中与 UI 数据源交互的呢?
这里我们看到 UICollectionView 数据源 的一个示例的实现 如果你用过 UITableView 或 UICollectionViews 那你以前见过这个 这提供了三个方法 包括协议必须的两个方法 很简单 对吧 我们已经询问了 Section 的数量 和每个 Section 中 Item 的数量 在内容渲染方面 我们会要求返回 Item 对应的 Cell 非常简单 到现在它已经 为我们服务十年了 对吧 它有几个优点 超级简单 你可以立刻推理出来 如果你只想提供两个方法 Section 中的 Item 数量 如果你的数据源是一维的 那就很简单了 你可以很快地对它进行迭代 但它也很灵活 对吧 因为你不需要 使用任何特定的数据结构 来支持你的数据源
它可以像一维数组 一样简单
如果你的数据源 有多个 Item 和 Section 它可能是二维的对吧 非常简单 非常直接
App 通常 比一维或二维数组 要复杂一些
而且 App 每年都变得越来越复杂 它们做的事情更多 我们的用户需要更多的功能 通常这些数据源 是由 App 内部的 复杂控制器支持的 这些控制器可以做很多事 它们可以与 Core Data 交互 还可以与 Web 服务对话 它们做了 很多不同的事情 我将很快地进行展示
让我们来看看 UI 层和控制器层之前的对话 这个控制器层做了很多 繁重的工作 来获取数据对吧 对话一开始很礼貌 就像是 “嘿 请告诉我 Section 中 Item 的数量 或者在我们渲染内容时 给我对应的 Cell“ 非常简单 到目前为止一切顺利
但随着时间的推移 事情会变得更加复杂对吧 比如这个控制器 有一个 Web 服务请求 在这里得到响应 对吧 就像是我有你的 推特之类的数据 对吧 现在这个控制器层 它本身是复杂的 要让世界知道 嘿 我改变了 有一些地方变了 这就是事情变得 有点复杂的地方对吧 现在由 UI 层决定 嘿 事情变了 我现在要根据这个改变 对我们的 UI 层进行更新 这包括所有针对 TableView 和 CollectionView 的变化 可能会有点复杂 我们在去年的 UICollectionView 一览会议中 讨论了这种复杂性以及如何正确 构造批次更新 以及如何修改备份储存 诸如此类的
但是有时候 不管你怎么努力
你知道事情总不会顺利 这是一个不完美的世界
从笑声中可以看出 你以前可能也遇到过这种情况 对吧 这并不罕见 这真的很令人沮丧 对吧 你遇到这种情况 然后会想 "好吧 我做错了什么?" 这是我本人 当你深入研究你的代码后 你在 Stack Overflow 上查询 看看发生了什么 最终你可能会灰心 只能调用 reloadData 我们去年讨论了这个 很好 这是正确的做法 你的 App 会正常运行
当你调用 reloadData 时 你会得到一个非动画效果 它会降低用户体验
所以这不好
我想用这一张幻灯片来讲讲哲学 就一张 我保证出了什么问题呢 问题是 我们的真相在哪里
你知道的 我的意思是谁造成了这一切 谁能解决这些问题
这里最大的问题是 我们的数据控制器 或者说是作为一个数据源 有它自己版本的真相 随着时间的推移而变化 UI 有一个版本的真相
UI 层代码负责 调节两者 确保它们总是同步的 正如我们所看到的 有时候这很难
所以我们目前的方法容易出错 主要是因为没有集中真理的概念
这就是最新的状况 这就是我们今天的处境 但是我们接下来会怎么样呢
我很高兴地宣布 对于 iOS tvOS 和 macOS 我们今年将推出一种全新的方式 我们称这个为差量数据源 好了让我们深入了解一下这是什么
没有 performBatchUpdates 我们继续 与此同时 所有的崩溃 困扰和繁杂 所有你不想处理的东西 都被抛弃了
我们只有一个 被称为 apply() 的方法 什么是 apply() apply() 是简单的 自动的 省事的差异化对比
我们用一个全新的构造 称之为快照 这是一个非常简单的想法 这实际上是 当前 UI 状态的真相 它不是 IndexPath 而是一组 唯一的 Section 标识符和 Item 标识符
你不是使用 IndexPath 进行更新 而是用标识符 让我们来看看 这里发生了什么
我是个很有创意的人 屏幕上有 FOO BAR 和 BIF 对吧 这就是我们互动的对象 这些是 App 中的标识符
假设控制器改变了 现在我们有了这个 我们想应用的全新的快照 但这是我们当前的快照 我们如何从新的事实
得到当前的快照
我们可以看到 用 BAR FOO 和 BAZ 配置了一个全新的快照 我们有些项目是 一直存在的 只是改变了顺序 然后有个新的项目进来了 从概念上来讲 apply() 知道 当前的状态和新状态 然后应用到 UI 元素上的
没有第二步 这就完成了 那我们该如何实现呢 我们在所有平台上 有四个类 对于 iOS 和 tvOS 我们有 UICollectionViewDiffableDataSource 以及 UITableViewDiffableDataSource 在 Mac 上 我们有 NSCollectionViewDiffableDataSource 所有平台都通用的是 这个 Snapshot 类 它负责当前的 UI 状态的 NSDiffableDataSourceSnapshot
背景就介绍到这里 我们接下来看一些代码 为此我会让我的同事 Troy Stephens 出来 Troy 非常感谢 Steve 今天我很高兴 带大家一起看一些 使用这个强大而又 漂亮简单的新 API 的例子 因此如果你还没有 下载本讲座的示例项目 请务必下载 这样你就可以 在空闲的时候跟着学习 最重要的是 用这个例子来 真正理解所有这些东西是如何工作的 它没有很多代码 其实很简单 当你查看这个示例项目时 你会注意到 除了我们今天将要查看的 三个使用 DiffableDataSource 的示例之外 这个项目还包含了 我们在 215 会议中引入的 功能强大的 新组合布局 API 的示例 这些例子恰好使用了 DiffableDataSource 作为一种非常简单的方法 将示例内容填充至 CollectionView 中 让我们操作演示机器 一起来看一看
我们的演示 App 在这里 当我们今天 讲解不同的例子时 我们会注意到一个重复的模式 这是一个简单的三步过程 任何时候你想 把一组新变化 新数据 放到有完整数据源的 CollectionView 或 UITableView 中 你只需创建一个快照 用要在更新周期中 显示的项目描述 填充快照 然后应用快照 更改将自动被 提交到 UI DiffableDataSource 负责 所有对 UI 元素的差异化对比 和发布 UI 元素的更改 我们来看一个具体的例子 我要打开 Mountain Search
这是一个很典型的 搜索 UI 对吧? 我们都能看到它 并推断出它的作用 例如你可能在 联系人 App 中看到这一点 而在本例中 我们正在查看 世界各地的山峰 你可以想象 在顶部有个搜索框 当我开始输入搜索字段时 我们希望看到 列表自动过滤 只显示匹配项 我们会看到如果我开始输入 我们做到了这一点 这一切都是 自动发生的 还伴有优秀的动画
这都是非常容易做到的 用非常少的代码 使用 DiffableDataSource 实现 我们来看看它是如何工作的
对于本例 查看 MountainsViewController 源文件
所有的行动都是从 用户在搜索栏中进行输入 开始的对吗 这里有一个回调 searchBarTextDidChange 它将被发送至控制器
从那里我们调用 我们自己的 performQuery 函数 传入的参数是 我们从那个搜索栏得到搜索文本 performQuery 本身 非常简单 我们所做的就是调用 我们的 mountainsController 这是我们模型层的对象 我们要它提供一个经过过滤的 排序的山峰列表 与我们的搜索词相匹配 我们现在有了这个山峰列表
我们经历了我提到的 三个步骤 我们创建了一个新的 NSDiffableDataSourceSnapshot 这个快照最初是空的 里面什么也没有 所以由我们来填充 我们想要的 Section 和 Item 在本例中 我们只显示一个 Section 我们只需添加一个 Section 我们可以称它为 主 Section
接下来我们添加 在此次更新中显示 Item 标识符 从形式上来讲 我们通常在这里传递 一个标识符数组 但是在 Swift 中你也可以 通过使用你自己原生的类型 使传参变得更加优雅 如果你有一个原生类型 它甚至可以是一个值类型 比如一个结构体或一个枚举 如果该类型是可哈希的 那你就可以根据 你所做的 Swift 语义传递 你的原生对象 我们过一会儿会 了解它是如何工作的 我们现在已经构建了快照 可以进行下一步了 我们所要做的就是调用 我们的 DiffableDataSource 让它应用快照 将差异展现出来 DiffableDataSource 运行时 会自动找出 上一次更新和 下一次更新之间的变化 请注意这里根本没有代码 我们不需要停下来并找出 上一个更新周期中 在用户输入当前字符之前 显示的内容是什么 一切都是自动处理的 没什么好担心的 我们不是在处理 IndexPaths 它们脆弱又短暂对吧 它们指的是 某个特定的更新 在不同的更新中 有着不同的含义 我们处理的标识符 是鲁棒和持久的 所以这里的操作 非常简单
在我们离开这段代码之前 我希望你注意到一些 关于 Snapshot 的事情 你可能已经注意到了 它是 Swift 中的一个泛型类 所以它的参数是 我们决定使用的 Section 标识符类型和 Item 标识符类型 首先看 Section 标识符类型这比较琐碎 在一般情况下 这是一种非常方便的技术 你只需要一个 Section 对吧 你可以为此声明 一个枚举类型 Swift 中枚举类型的一个好处是 它们是 自动可哈希的 为它们添加了可哈希性 我们这里有一个枚举 和一个 case 语句 没有其他的了
对于我们的 Mountain 类型 我们将查看 MountainsController 也就是模型层 我们在这把 Mountain 声明为一个 Swift 结构 我们声明结构类型 为 Hashable 这样我们可以将它与 DiffableDataSource 一起使用 而不是传递标识符 重要的要求是 每一座山都要用 它的哈希值进行唯一识别 所以我们通过给每座山 自动生成唯一标识符 来实现这一点
在这里我们遵循了承诺的可哈希性 我们只用那个标识符来 提供哈希值 这样我们就可以 找到每一座山 虽然每座山是值类型 只是通过复制来传递 没有可供引用的指针 但是标识符和 特定于该标识符的哈希值 是它们足够独特 以便 DiffableDataSource 可以追踪它们 从一个更新 到下一个更新 作为可哈希性的一部分 我们也在这里进行了 相等测试 因此我们已经了解如何 对 DiffableDataSource 发布更改
让我们回到 MountainsViewController
非常方便的是 我们创建了一个名为 ConfigureDataSource 的函数 我们在其中配置数据源 代码量 真的很少
在本例中 我们使用的是 UICollectionView 所以我们实例化一个 UICollectionViewDiffableDataSource 我们传递的参数是 Section 和 Item 类型 把一个指向 我们想要使用的 CollectionView 的指针 也传递过去 DiffableDataSource 会接受 那个指针并自动 接通自身作为 CollectionView 的数据源 我们不需要继续操作
最后我们有这个 尾随闭包参数 用于 DiffableDataSource 的初始化 所有这些 都是你通常需要写的代码 如果你从头开始 实现你自己的数据源 你将要实现 cellForItem(at: IndexPath) 方法 这是数据源回调方法 和我们在此处做的工作 一模一样 我们回调至 CollectionView 并请求它 提供适当类型的 Cell 显示我们想要的数据 我们用想要显示的内容 填充该 Cell 然后将其返回 所以这只是使用了 cellForItem(at: IndexPath) 代码 并方便地将其移植到 一个很好的闭包封装中 是我们在实例化数据源时 传递的 有一个很好很方便的 不同在于 除了提供我们 要求的 Item IndexPath 之外 也提供了其标识符 在本例中 是原生的 Swift 值类型 这对应于我们想要 显示的特定 Item 所以我们把 mountain 作为参数传递 没有更多的工作要做 我们不必使用 IndexPath 去查找 它属于哪个模型层对象 我们只是把 mountain 作为参数传递 我们获取到山的名称 并将其设置为该 Cell 的 标签文本
这就是全部内容 关于如何设置 和配置 CollectionView 的所有其他内容都与之前相同 在这个示例代码中 没有隐藏任何 performBatchUpdates() 代码 这就是所有内容 非常简单 来看看另一个例子
这里我们有一个来自 iOS 熟悉的 Wi-Fi 设置 UI 模型 这个只比上一个 稍微复杂一点 因为我们在这里 有两个不同的部分 我们在顶部有个 叫 Config 的部分 其中有 Wi-Fi 启用/禁用开关 并显示我们 连接的当前网络 在这下面我们有另一个动态更新的部分 向我们展示了 检测网络的列表 供我们连接
另外需要注意的是 如果我们点击 Wi-Fi 禁用开关 或重新打开 我们会看到一个流畅的 动画的 UI 折叠或展开 所有这些都可以使用 DiffableDataSource 轻松实现 让我们来看看这个 动态 UI 是如何实现的
转到我们的 WiFiSettingsViewController
我们将查看 updateUI 函数 我们将该函数命名为 updateUI 我们已经注意到确保 在我们需要显示的内容 发生变化时它都会被调用 大多数时候 可能是因为我们检测到的 当前可用的网络集合发生了变化 但也可能是因为 用户切换了 Wi-Fi 启用/禁用 按钮 出现任何改变我们 UI 的东西 我们都确保会调用它
所以我们在这里仍然有 相同的三步过程 获得我们想要显示的数据后 我们从获取 配置项目开始 因为我们通常需要这些 我们继续创建一个快照 这个快照最初也是空的 那就让我们用我们想要 展示的东西填充它
我们添加的第一个 Section 出现在顶端的配置部分
我们添加它的 Item 所以会有一个或两个 Item 是取决于 Wi-Fi 是否启用
如果现在启用了 Wi-Fi 我们也会想和后端 和模型层交流 索要可用网络的列表 我们将把这个列表 包装成一些我们 在稍后会看到的项目类型中
我们为该网络列表 添加一个 Section 然后我们要添加 那个 Section 中的 Item 请注意 我们在这里有 两个不同的 Section 我们可以明确哪个 Section 添加了 Item
就是这样 我们准备好了 我们已经描述了所有我们想展示的内容 所以我们只需让 DiffableDataSource 应用这些更改 可以以动画的形式展现差异 可能有时候 你想要选择 不用动画展现差异 例如 当你第一次打开 UI 并显示初始数据集时 你可能想 也可能不想要动画 通常你希望它是即时的 因此你可以将 animatingDifferences 设为 false 就像我们在本例中做的一样
看我们这里使用的类型 我们将一个 Section 类型 和一个 Item 类型 作为参数提供给 DiffableDataSource 回到顶部我们可以看到 正如我们想象的一样 Section 仍然是枚举类型 我们在这里需要 两个不同的 Section
再次 作为枚举类型的 Section 在 Swift 中是自动可哈希的 所以我们很高兴
然后我们在这里声明了一个 Item 类型 这是一种结构体类型 与 Mountains 一样 我们声明它是可哈希的 声明这个类型的原因是 当我们查看列表时 它主要包含列表是 其中的网络项目 但除此之外 上面还有个不同的项目 就是 Wi-Fi 启用/禁用开关 那不是网络项目 所以我们这里有一个异构列表 我们所做的就是 用这种通用包装器类型 封装每个 Item 但是由于这个包装器类型 是我们要传递给 DiffableDataSource 的项目类型 我们必须注意确保 它是可哈希的并且 项目是由哈希值 唯一标识的 所以对于网络项目 我们可以从 netowrk Item 得到唯一标识符 移植到 Network Item 中
对于配置项目 我们只是动态 生成 UUID
再看看我们的 哈希函数 它只是基于唯一标识符 计算哈希值 而这就是 DiffableDataSource 能够 识别从一个更新周期 到下一个更新周期时相同的项目所需的全部内容
让我们看看 配置数据源的位置
这与之前非常相似 除了这次 我们用的是 UITableView 从创建和提交 快照的角度来看 这并不重要 API 非常相似 但对于设置 我们必须实例化正确类型的 DiffableDataSource 我们有一个 UITableViewDiffableDataSource 我们用将要使用的 Section 和 Item 类型作为参数 然后传递一个 指向 TableView 的指针 它将进行连接 把 DiffableDataSource 作为数据源
最后我们得到了 提供 Item 的尾随闭包 乍一看起来 这更复杂 但实际上只是因为 我们有各种不同类型的项目 我们要显示的项目是异质的 基本上有三种类型的项目 我们以不同的方式处理它们
但是这段代码中 即使我们没有使用 DiffableDataSource 它也会存在 它会在 cellForItem(at: IndexPath) 方法中出现 设置这个 UI 很简单 甚至配置 DiffableDataSource 也不是那么难
最后一个例子 可能是最有趣的 这里我们有一个 UICollectionView 它显示的项目 表示为色卡 它们一开始是 随机混色的 如果我点击 Sort 按钮 我们可以看着它们被迭代排序 为频谱顺序 所以除了观看时令人着迷 和有趣之外 这要归功于 Steve
除了观看时非常迷人 和有趣之外 这个例子与我们在其他例子中 构建和提交 更新的方式 略有不同 所以如果我们想 如果我们的目标只是 把所有的东西排序然后 跳到最终状态 我们可以这么做对吧 这个演示程序的设置 使我们能够在 每个中间阶段观察 迭代排序过程 为了做到这一点 我们的排序功能 会经过每个阶段 并一步步给我们提供结果 它为我们提供了 每个连续的新状态 每次发生更新时 我们都会创建一个快照 并应用快照 才有了这个 美好有趣的动画视图
来看看我们是 如何实现它的 以及它的不同之处
我们将在这里查看 InsertionSortViewController
所有有趣的动作 都发生在 PerformSortStep 函数中
正如我所说 总是有三步循环 我们将获得一个快照 填充它然后应用它 但在这种情况下 我们没有创建 新的空快照 而是利用 DiffableDataSource 的功能 请求当前的快照 现在这个快照 预先填充了 当前 CollectionView 看到的 UICollectionView 中 显示的内容的真实情况
所以我们不必从头开始 我们可以从该状态 开始并计算下一个 中间状态在这里 我们填充 Snapshot 我们将看到熟悉的 appendItems 函数被调用 但我们这里也有一个 deleteItems 函数 当你查看到 Snapshot API 时 你将会看到有各种各样的 功能可以在你 进行此类用法时 修改现有 Snapshot 你可以将 Item 从一个地方 移到另一个地方 以此类推 但在其他方面 和之前没有什么区别 我们只是想 设置我们想要显示的新的最终状态 我们使用的是标识符 而不是 IndexPath 这点很好 最后当我们完成时 我们所要做的就是 将 Snapshot 应用于 我们的 DiffableDataSource 我们得到了这个好看的 渐进式排序 非常好 谢谢 这就是我们设置 DiffableDataSource 的地方 这是用于 UICollectionView 我们指定我们使用的类型 CollectionView 我们还有提供 Item 的闭包 也很简单 因为我们只是 显示这些色卡
所以通过这三个例子 我们可以看出 创建这些 动态 UI 所需的代码很少很简单 这些 UI 对更改也有非常强的鲁棒性 我们可以进行更改 而不必担心在代码中 出现奇怪的异常 它们的鲁棒性都很强 已经融入到了 API 的工作原理中 我们现在确实触及了一些 有趣的细微差别 特别是对象 唯一标识的重要性 如果你使用的是 Swift 类型 这些 Swift 类型需要 符合的要求是 必须可哈希 让我们进入更深的研究 使这些问题成为 讨论的焦点 我现在要邀请我的同事 Steve 再次上台 谢谢 通过所有的演示 我对这个 UI 是如何工作的 有了一些了解 我想对如何充分利用 这个 API 进行 更详细的讨论
好的 首先 正如我们在整个演示中看到的 基本上有三个步骤 你希望创建一个 Snapshot
根据你的需要来配置它 然后应用它 所以你总是希望调用 apply() 方法 而你不需要再 调用 performBatchUpdates 方法了 那已经过时了 也不需要 insertItems 都没有了 如果你调用这些函数 框架会抱怨 你知道 你会看到的创建快照 有两种方法 最常见的方法 是创建一个空的快照 在这里我们看到 我们用 Section 和 Item 类型 构建 Snapshot
你也可以创建一个 就像我们在最后一个 演示中看到的那样 当某个动作发生 你需要修改 一个小地方时 这非常有用 现在当你创建它时 你将得到一份副本 所以你可以随意改变它 它不会影响 它的数据源
一旦你有了这个快照 如果你提出了一些问题 比如 Item 的数量是多少 Section 的数量是多少 识别标识符 你都可以做到 你可以在 SDK 中 查看到很多 API 这里只展示了一些
我保证过 不再有 IndexPath 因此当我们配置 这些快照时 你将永远不会通过显示的 API 看到 IndexPath 所以到目前为止 我们已经看到了一种 非常常见的添加 Section 和 Item 的模式 诸如此类 但你也可以执行 插入 移动 和删除等操作 所有这些 API 都采用 其他相对标识符 来进行标示 如果我想插入 20 个 唯一的新标识符 在另一个标识符之前或之后插入 我们完成任务的 明确的 API 所以你会说 在这个标识符之前 插入这些标识符 现在如果你在特定 Section 中 没有任何内容 则没有标识符可以 锚定插入或移动 这就是我们提供 append API 的原因 你可以添加 Section 和 Item
现在在你熟悉的路径中 你有许多 Section 你在这里配置你的快照 你可以循环遍历 Section 数据 在这种情况下 可以在不指定 Section 的情况下添加 Item Swift 中有一个 默认参数指定为 null 在这种情况下 是默认添加到最后一个已知的 Section 这使得代码非常美观
我们再来谈谈标识符 这些必须是唯一的 这不是一个大问题 因为大多数 App 在其模型对象中都有 某种身份概念 因此使用该唯一标识符 是很自然的步骤
现在在 Swift 中 需要符合可哈希的要求 这很方便 Swift 中的很多东西 都会自动完成 我们在枚举类型中 看到了这种自动合成
我们有字符串 整数和 UUID 所有这些可用于 DiffableDataSource 的东西
现在我们看到了 你可以将一些模型数据 引入这些标识符 这真的很方便 现在你的身份需要来自 某个唯一的标识符 但你也可以引入其他属性 当我们看到山峰的名字时 也可以找到我们例子中的对象 这非常方便 因为当你配置你的 Cell 时 你所需要的所有东西 都在这里 别去别的地方找了
这是一个小的快速模版 我们在整个示例中一直有看到 关于如何 在 Swift 创建可哈希的结构体非常直观
那么基于 IndexPath 的 API 要怎么处理呢 我们有 CollectionView 和 TableView 它们有大量基于 IndexPath 的 API 其中很多都在 Delegate 方法中 因此如果用户与内容交互 并点击某个项目 你将得到这个熟悉的 Delegate 消息 didSelectItemAt indexPath
但是我们已经进入了这个 基于标识符的新世界 我们将如何处理 这个 IndexPath 你知道那是老一套 所以我们这里有新的 API 让你在标识符 和 IndexPaths 之间进行转换 然后从 IndexPaths 转化为标识符 所以这里我们看一个例子 我们正在使用过去的 IndexPath 并将其转换回标识符 这会在常数时间内完成 这非常非常快
说到性能
我们做了大量的工作 让它尽可能更快 还有很多 低层次的东西非常重要
如果你学过 计算机科学 关于差异对比是如何发生的整个概念 你会知道这是 一个 O(N) 的线性运算 而简单来说 它只是意味着你的 Item 越多 你进行差异对比的时间越长
因此在开发过程中 衡量 App 很重要 我们都知道这一点 我们希望确保 主队列尽可能空闲 以便真正响应用户事件 我们渲染的非常快 所以当你在测试你的 App 时 你们都会测试 App 在开发过程中 尤其是在结束时 我想确保主队列上的尽可能的没有内容
如果你发现线性差异对比中 有大量 Item 需要花费 额外的时间 那么从后台队列 调用 apply() 方法会比较安全 真正酷的是 我们为了支持而使用的 API 的数量 没有 API 这就是最好的 API 对吗 那么如果从后台队列 调用 apply() 会发生什么 实际上 框架足够聪明可以知道 现在不在主队列中 它会说 让我们继续 在这里进行差异对比
一旦计算出差异 我们就会跳到主队列 应用我们差异对比的结果 程序就像往常一样继续
只有一个忠告 我保证就一个 如果选择此模型从 后台调用 apply() 则应保持一致 永远都从后台队列中调用它 你永远不希望发生混乱 一会从后台队列 一会儿从主队列调用它 请始终用同样的方法
我们是好公民 如果你弄错了 我们会抱怨的 所以在 Apple 公司 合作是很重要的一部分 这是我们组织的主要力量 是我们彼此交谈 和共同解决问题的方法 作为框架的作者 这其中的一部分是 确保你所有的客户 或者你经常与之交谈的人 找到困扰他们的问题所在 这显然是正在困扰他们的问题之一 在这期间我们和那些正在制作 Share Sheet 的人聊了聊 这是 iOS 13 中 重新设计的新 Share Sheet 具有出色的隔空投送扩展功能 当他们拥有这个全新的设计时 他们才发现 他们说 哦 这看起来很棒 我们需要这个 他们确实做到了 因此我想让一位 来自 Share Sheet 的同事 Jacob Klapper 来指导 我们完成这项工作 Jacob 大家好 我很高兴向你们 展示 Share Sheet 如何利用 iOS 13 中 新的 CollectionView API
我们在全新的 Share Sheet 中 Share Sheet 实际上 利用了新的 组合布局 API 和 DiffableDataSource 但 DiffableDataSource 真正闪耀的地方在于 全新的隔空投送扩展
因此隔空投送扩展程序 有一个浏览设备的浏览器 实际上我们已经 使用 UUID 来唯一标识 发现的每个设备 因此当发现新设备时 我们可以创建 一个空的快照啊 附加我们的 Section 和 Item 并应用差异对比 DiffableDataSource 负责其余部分 无论移除或 删除多少 Item 动画都很漂亮 DiffableDataSource 对我们来说 已经改变了游戏规则 我们迫不及待地想看看 你在 App 中用它做什么 现在舞台还给 Troy 听听他最后的想法
天呐 听到 DiffableDataSource 在我们自己的 App 中 发挥了如此大的作用 我非常兴奋 我们非常高兴 让我们内部采用的 API 能够在我们的 平台上供开发者使用
我们今天已经看到 DiffableDataSource 极大地 简化了将模型数据 放到 CollectionViews 和 UITableViews 中的工作 我们认为这真正改变了游戏规则 它使这个过程非常简单和鲁棒 不会再有令人困惑的异常 在调试和难以编写的 批处理代码中出现 你可以专注于 你想让你的 App 做什么上 把其他的留给框架 今天你可以在 iOS tvOS 和 macOS 上 使用 DiffableDataSource 除了为你计算差异对比 并自动将它 提交给 UI 你能得到这些 漂亮的动画对吧 你不需要做额外的工作 就能得到那种 令人愉快的用户交互效果 内置的差异对比很快 它经受了严峻的压力测试 DiffableDataSource 是一个鲁棒的 API 你可以使用它 并运行它 快行动起来吧 在你的 App 中使用 DiffableDataSource 我们迫不及待地想要看到 这将减轻你的负担 你将能够用更少的时间 更少的烦恼 来创造令人愉快的用户体验
如果你觉得这个讲座有趣 而且你正在使用 CollectionViews 我们还有另一个 你会非常喜欢的会议名为 Advances in Collection View Layout 我们描述了一个全新的 布局系统 它可以简单地描述 你想要在 CollectionView 中 拥有的任何自定义布局 并且能够看到 它的实现 而不需要任何高性能的结果 所以我们觉得你会喜欢的 一定要参加那个会议 谢谢大家今天的收看 [掌声]
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。