2022 年老司机技术参与组织的 WWDC22.playground Day 3 聚焦当时的 Beta 与技术探索。演示结果来自嘉宾的实验;可稳定依赖的接口范围以 Apple 公开文档为准。
新框架发布时,最吸引人的往往是一段很短的演示代码。但真正把它用进产品,需要继续回答几个问题:它替开发者做掉了什么工作,代价转移到了哪里,遇到性能或兼容问题时又能看见多少?
WWDC22.playground Day 3 用两场实践和一轮圆桌回答这些问题。黄晨志主持,胡思华把 Swift Charts 与手工绘制图表放在一起比较;吴子齐从 ARKit 的基本概念出发,演示如何识别墙面并放上一幅图片。随后,EF、木木等嘉宾继续讨论锁屏组件、开发者模式、专注模式以及开发工具的更新。新能力不是一个名词列表,而是嵌入现有工程后的具体选择。
第一场实践:同一张折线图,两种实现方式
思华先说明比较方式:用同一份数据和相近的展示尺寸,分别实现新旧两种图表。目标是观察表达方式、代码工作量和呈现效果,而不是证明某个框架在所有场景中都更快。
使用 Swift Charts 时,他围绕数据构造图表,为每个数据点提供横纵坐标,再用 LineMark 表达折线。随后调整线宽、颜色、圆角等样式。为了让对比集中在绘制本身,演示还隐藏了部分坐标轴,并通过辅助容器统一尺寸。
这个过程把两种责任分开了:数据和图形之间的关系由图表框架表达,具体视觉样式则通过修饰继续调整。开发者仍然能决定线条怎样显示,但不必为每一张图都从路径、坐标换算开始搭建基础设施。
现场先给两张图同样的容器尺寸,再用预览把结果上下排列,避免因宽高不同误判实现差异。旧实现用 Shape 和 GeometryReader 取得绘制空间,把数据点换成路径,还要处理画布坐标方向;新实现把数据逐项交给 LineMark,样式由修饰符调整。两张图最后看起来相近,但“调用处只写几行”掩盖不了自定义组件内部路径计算、坐标变换和后续维护的工作。
折线完成后,他又临时换用柱状标记,说明数据仍可沿用,图形表达可以换成另一种类型。修改线宽、圆角、颜色以及隐藏坐标轴都在同一套表达中完成。这个演示不是一份复杂报表的完整实现,但足以让人看见:当需求不断增加图表种类时,自行维护的 Shape 封装会跟着膨胀。
他还分享了对图表底层渲染的观察。现场没有跨设备的性能基准,Metal 支持也不等于在所有项目中都比手绘更快。演示能直接说明的是:对于框架已经覆盖的表达方式,Swift Charts 减少了自行组织绘图逻辑的负担;具体性能仍要按数据量、交互和目标设备测量。
SwiftUI 进入已有项目,可以从局部开始
第一场演示之后,主持人没有立即转入下一项新功能,而是继续问:SwiftUI 到底怎样把上层描述变成屏幕内容,已有 UIKit 项目又如何采用?
讨论提到 UIHostingConfiguration,即在现有列表单元格中使用 SwiftUI 内容的方式。Apple 的WWDC22 课程《Use SwiftUI with UIKit》确实演示了这条路径,包括在单元格中放入图表。
这个变化的意义在于,采用新框架可以从一块具体内容开始,而不必把整个应用一次性重写。对已经有大量 UIKit 页面和业务逻辑的团队,局部验证更容易回答“这项技术是否适合当前问题”,也更容易把用户体验与维护成本放在同一张表上比较。
他给出的现场数字是,在一次 UIKit 页面改写并以 A/B 方式观察的案例中,业务实现代码约减少四成,同时团队关注的产品表现没有明显折损。他还观察到,新人可以通过声明式结构和预览更快理解一个页面会怎样显示。主持人随即提醒,现场的小 Demo 改一行就能看见结果,大型存量项目仍有编译和依赖成本;思华认可这一差别。
写得更少之后,更需要看清数据如何影响界面
EF 提出了更接近生产使用的问题:代码少了,运行和调试会不会变得更难?有哪些坑需要提前知道?
思华的回答没有否认代价。声明式框架替业务层承担了大量工作,因此有些复杂度会从显式代码转移到框架执行中。开发者仍然需要把数据的来源、依赖关系和变化范围设计清楚,否则一次状态变化可能影响到原本不想更新的其他视图。
他举的典型问题是,某个属性本来只应改变 A 视图,却因为数据组织或依赖关系,使 B、C、D 也重新参与计算。这类问题不一定能从最后一张截图看出来,却可能在频繁更新时影响体验。
思华还提到,错误的数据依赖甚至可能让图计算出现循环。这比“界面刷新有点慢”更严重,提醒开发者把状态变化的来源和传播范围梳理清楚。SwiftUI 帮忙处理安全区域、深浅色、无障碍文字和动画等通用工作,简化了业务代码;这些自动处理本身也形成需要分析的依赖图。
判断更新范围时,节目建议先使用可观察的工具信号,例如检查 body 被求值的频率,再结合实际渲染与耗时分析。需要保留其中的区别:body 被重新计算,并不等于每一次都会发生同等范围的屏幕重绘。把二者混为一谈,会让性能分析失去准确性。
为了进一步解释,思华展示了自己研究 SwiftUI 内部依赖关系的图,把计算节点、数据流和最终显示描述联系起来。即使是简单的文本,也涉及布局、环境、无障碍与动画等许多处理。这是他分析框架的视角;图中的私有节点名称不是开发者可以依赖的稳定 API。
从这些观察中,他提炼出的实用原则比较明确:尽量让无关的数据变化不传播到不需要更新的内容;对确实不需要动画的部分,避免让它无谓地跟随动画时间变化;出现异常计算时,先确认依赖关系,而不是只在最终绘制处加优化。
他用最简单的 Text("Hello World") 展示研究图:为了把文字放在合适位置并输出,内部还需要布局、环境、内容解析和显示列表等节点;某个节点依赖的数据若没有变化,就不必再次求值。动画还会把时间变化带入依赖关系,所以无须动画的部分应避免被这条变化链牵动。这里的图用于解释性能判断,私有实现名称不应成为应用代码的依赖。
节目也谈到把复杂绘制组合交给不同渲染方式处理。这需要针对具体视图实测;一个页面少写了绘制调用,不一定意味着内存、离屏合成或其他成本也会下降。
锁屏与组件:一个更近的入口,也是一种更严格的产品约束
EF 把讨论从应用内部带到 WidgetKit。桌面和锁屏上的内容与普通页面不同:更新由系统安排,开发者不能把它简单当作一个一直运行、随时刷新的小应用。
EF 先对比了传统组件的 Timeline:内容更新由系统调度,不能当作普通应用界面随意刷新。Live Activities 的预览让他想到配送或等待进度,但当时尚未看到完整技术课程,因此只提出“能否减少重复推送”的产品问题,没有给出一个可直接复制的更新方案。
他还注意到锁屏组件和手表组件的外观约束,以及当时展示的单色、着色形式。这让设计问题比“把原有桌面组件缩小”更具体:用户只看一眼时要读到什么,系统限制了哪些样式,哪些信息应该随时间改变?嘉宾随即承认,Live Activities 究竟和组件或通知怎样配合,还要等后续技术资料,不能凭发布会画面直接写刷新逻辑。
社区还提出了与当时生活有关的点子,例如把有时效的信息放到锁屏,减少查找步骤。随后有人提醒,这类内容可能涉及隐私,必须考虑锁屏可见范围与他人读取的风险。这段讨论的重点并不是某个点子现在是否仍适用,而是一个新的显示入口出现后,便利和信息暴露需要一起设计。
对于常亮显示等当时尚未确认的方向,嘉宾表达的仍是期待,与已经公开的 WidgetKit 更新分属不同范围。
第二场实践:AR 会话、锚点与渲染,各自负责什么
吴子齐开始 ARKit 实践。他没有直接从一段庞大的代码进入,而是先拆开四个概念。
ARSession 管理与现实环境交互的会话;配置决定这次使用哪类跟踪能力;锚点为需要放置的内容提供空间参照;渲染技术负责把虚拟内容显示出来。识别现实环境和把模型画到屏幕上相互协作,但并不是同一件事。
他用相机输入、运动信息以及其他感知能力,解释应用怎样形成对空间的理解,再由 SceneKit、RealityKit 等选择完成可见的内容。这样拆解之后,开发者更容易知道问题属于哪一层:没有正确识别平面、内容放错位置和材质显示异常,需要检查的对象不同。
本场选择 Objective-C、ARKit 与 SceneKit,目标是识别一个竖直平面,并在上面放置图片。这个选型也照顾到当时仍以 UIKit 和 Objective-C 为主的开发者,让新能力可以从熟悉的视图结构进入。
实践的第一步是创建 ARSCNView,设置视图与代理,并在开发中打开调试信息,观察特征点与跟踪过程。随后检查目标配置是否受支持,启用需要的平面检测,再启动 session。
子齐把演示目标限定为检测竖直平面,配置中开启相应的 plane detection 与自动对焦。启动 ARSession 后,相机流出现并不代表平面识别已经成功;他还建议实现 session 的错误回调,把配置或跟踪中的异常单独记录。打开调试显示后,屏幕上的特征点能帮助判断相机是否取得足够的环境信息。这样,开发者可以区分“会话没跑起来”和“会话在跑,但墙面尚未可靠识别”。
这里反复强调了能力检查。ARKit 虽然提供统一的软件接口,不同设备与系统仍可能支持不同能力。开始运行前就检查条件,比等待一个始终不出现的效果更容易定位问题。
能力也有层次:发现一个平面,与进一步给平面分类,并不是同一项保证。子齐在新增锚点的代码里检查分类能力和结果,指出较复杂的识别可能依赖更新的硬件。至于演示中几部手机识别快慢不同,他把特征点数量与画面中的纹理、对比度一起拿来观察;不能只用摄像头数量解释每一次成败。
墙不是一次识别完成的:处理新增、更新与移除
演示进入代理回调。子齐把它分为新增、更新与移除三个阶段。
刚开始扫描时,系统可能只确认了一小片表面;随着手机移动和信息增加,对平面的认识会扩展或修正。因此,应用不能在第一次发现锚点后就假设位置与范围永远不变。新增回调用来建立内容,更新回调用来跟进变化,移除则可能与重新组织或合并已经识别的平面有关。
演示代码在新增锚点时创建节点,在更新回调里根据新的范围调整它,并用锚点标识关联同一个对象。两个起初分开的平面被判断为同一表面时,框架可能移除其中一个锚点;若应用另存了锚点到节点的映射,自己的记录也必须跟着更新。这一组回调说明,空间理解是持续修正,不是相机扫到墙的瞬间便永久完成。
子齐展示了不同手机上的演示效果,讨论识别速度、特征点和硬件能力的差异。某次演示未检出平面,并不能证明一款设备完全不支持。Apple 在2018 年 ARKit 1.5 的公告中已经公布垂直表面检测;旧设备上的失败不能直接归因于单摄。具体能力要看所用配置的支持检查,具体失败还要结合环境与代码确认。
具体操作是先给 ARSCNView 加手势,再用 hit-test 把二维屏幕坐标投射到三维场景,找到命中的平面或节点,把图片挂在相应位置。因为图片自身的平面方向未必与检测到的竖直墙面一致,还得调整节点旋转。这个过程把“检测墙面”和“在墙上放画”分成两个可以分别验证的步骤。
节目还处理了图片闪烁,说明视觉问题可能来自深度和材质设置,而不是环境跟踪。演示中调整的深度设置只针对这组对象关系,其他 AR 场景仍要检查自身的遮挡与渲染条件。
RoomPlan 与 ARKit 6:先理解现有设备,再等待新的设备
两场实践之间,嘉宾多次提到自己期待中的头戴设备并未在本届大会出现。但子齐也强调,现有设备上的 AR 能力仍在继续进步。
他关注 RoomPlan,是因为更容易使用的房间扫描能力可以降低应用尝试空间体验的门槛;他关注 ARKit 6,则是因为相机控制、图像获取等环节的进步,可能让 AR 与已有拍摄流程结合得更好。这是从具体工具出发的观察,不需要先假设某款未来设备何时出现。
问答末尾,有观众追问 LiDAR 如何应用到 ARKit 中。子齐说明,自己没有掌握所有底层参数细节;对于许多常规用法,开发者首先需要选择合适配置并检查支持条件,由框架整合可用的设备能力。这一回答没有把“框架帮助整合”扩大成“任何设备能力都完全无需配置”,也没有假装已经解释了全部传感器实现。
圆桌把新能力放回开发和使用流程
最后约 20 分钟并非两场演示的重复总结,而是继续提出了多项独立的观察。
开发者模式。 EF 介绍自己在 iOS 16 Beta 与新版 Xcode 上的体验,认为显式开启开发能力让设备使用者更清楚自己启用了什么。Apple 的当年课程把它限定在开发签名应用、调试与相关测试流程;App Store、TestFlight 和企业内部正式分发并不都要求这个模式。因此,不能把录播概括成“凡非 App Store 应用都必须开启”。
专注模式。 木木关注 Focus Filters:系统状态的变化可以影响应用内部呈现的内容,而不仅仅是允许哪些应用发通知。他从开发者角度谈应用如何声明可调整的行为,再从用户角度期待通信或效率应用配合不同情境显示合适的内容。技术入口最终要解决的是用户每次进入工作或生活场景时,需要反复手动调整什么。
木木把流程进一步拆开:应用先说明自己哪些内容或参数可随专注模式调整,用户在系统设置中为某个模式选择这些行为;模式切换后,应用再根据收到的状态更新内部呈现。他举即时通信的账号、内容范围与来电干扰作设想。主持人因此把问题从“有一个新 API”转成“切到工作模式后,用户少做了哪一步”。具体应用是否能切换账号或过滤来电,仍取决于它自己的实现和系统权限。
自定义布局。 思华关注网格与开发者定义布局算法的能力。相比只能在已有容器中组合视图,新的布局工具使更特别的排列成为可表达的对象。Apple 的WWDC22 布局课程介绍了 Grid、Layout 等工具。节目中的潜在应用仍是设想,实际采用时要结合自己的布局与缓存需求。
构建和内存工具。 主持人谈到构建时间线,关注编译、模块构建、链接及前后置脚本究竟谁占了时间;也关注内存图中对象关系与关联内存信息的改进。这里共同的价值是把“感觉慢”或“怀疑泄漏”变成更可定位的问题。线程运行、Run Loop 与临时对象积累的讨论,也是在寻找可观察的证据,不应概括为每个后台线程都必须以同一种方式运行。
他还以循环处理一批本地图片为例,担心后台任务持续运行时临时对象累积,想借助工具看线程活动与内存增长是否相关。这个现场推理不能直接推出“子线程都必须保活 Run Loop”或“对象必在休眠前才释放”;实际排查还应看任务结构、自动释放池和具体分配记录。录播对新工具的期待,最有价值的是提出可以观测的问题,而不是给所有线程套同一修复办法。
黄晨志举出一个更具体的内存问题:如果某个 ViewController 因引用关系未释放,只知道“它泄漏了”还不够,最好能看见它继续持有哪些对象、共关联多少内存。构建时间线同样把“编译太久”拆成模块构建、编译、链接和脚本。两项工具的共同点,是让下一次优化有可检查的起点。
Bitcode 与后台资源。 EF 谈到过去为了开启 Bitcode,需要协调依赖库支持的困难,以及看到其变化后的疑问。Apple 的Xcode 14 发布说明记录了当年的弃用变化;最终包体积会怎样,当时没有测量结果。子齐最后提到 Background Assets,希望系统提供更多后台资源准备的时机,但也说明自己还没有深入阅读,因而只是提出继续研究的方向。
这场实践留下的,是如何验证一个新能力
Day 3 从一张折线图开始,到在墙面上放一幅图,再延伸到锁屏、开发设备和构建工具。它的共同问题始终很具体:框架负责哪些工作,开发者仍需要负责哪些决定,出现意外时又怎样把问题拆开?
思华的实践提醒人们,不要被调用处很短的封装迷惑,要看整个实现和维护范围;子齐的实践则提醒人们,不要把一次视觉结果当成稳定的世界模型,要处理能力条件和持续更新。后面的圆桌把这两种态度带回产品:新入口能带来便利,也可能带来约束;工具更加自动化,并不意味着可以停止观察和验证。
