写点什么

SwiftUI @ Netflix:推动新技术落地是怎样一种体验?

用户头像
故胤道长
关注
发布于: 2021 年 05 月 02 日
SwiftUI @ Netflix:推动新技术落地是怎样一种体验?

背景


上周,奈飞新版的 iOS App 上线了苹果商店,其登录界面已经完全由 SwiftUI 重构。这是奈飞首次尝试 SwiftUI,也是笔者一手推动并实现的项目。


SwiftUI 是苹果于 2019 年 WWDC 推出的全新编程框架。它通过声明式语法,大幅优化了苹果全平台(iOS、iPadOS、tvOS、macOS、watchOS)的 UI 编程效率。它最低支持 iOS 13 系统,这也是目前奈飞的 iOS App 支持的最低版本。


据苹果自己说, SwiftUI 具备三大优势:


  • 可以用更少的代码来实现 UI

  • 声明式语法更加清晰易懂

  • 代码和预览界面即时同步


这三大传说中的优势,正是我决定尝试使用 SwiftUI 的初衷。


苹果官方给出的 SwiftUI 范例


项目启动


笔者从 SwiftUI 发布时,就进行了深度的追踪和大量的练习,对其性能和编程范式比较熟悉。同时,我还和前端的同事们宣扬了 SwiftUI 的种种特点和优势;由于奈飞的前端使用的主要框架为 React.js——其语法和 SwiftUI 莫名相像,前端的同事对于 SwiftUI 的好感和接受度很高。另外,作为增长团队的移动负责人,我还和 iOS 工程团队提前打好了招呼,确保如果我这里启动相关项目,能够从那里获得足够的支持。


群众基础有了,下一步就是搞定领导了。除了定期和我的直属总监“吹捧” SwiftUI 之外,我还完成 SwiftUI 项目的相关工程/产品文档。里面提及了使用 SwiftUI 的初衷(就是苹果所说的种种好处),调研了奈飞 iOS App 中最适合尝试 SwiftUI 的部分,以及相关的产品和工程指标。


之所以选择登陆界面,有三个原因:


  • 界面足够简单。登录界面的 UI 由图片、文字、登陆按键来构成,它变化较小。我们可以用 SwiftUI 来快速实现,以此验证 SwiftUI 的各种性能,为日后长期的工程方向选择提供依据。


  • 可以全方面检验 SwiftUI 的性能。登陆界面的数据并不存在设备本地,需要访问服务器端获得,同时图片和文字信息会随着季节、国家的变化而不时的变化——用 SwiftUI 来做登陆界面,不仅可以检测其实现 UI 的性能,还可以观察它异步访问网络的速度、调用 Objective-C 和 Swift 的兼容性、加载和缓存数据的效率。因为登录界面会面对大量的用户,我们还可以获得充足的数据以观察 SwiftUI 在多种设备、多个版本上的使用情况。


  • 登陆模块比较独立。它和其他模块的接触比较少,与其他模块的耦合性也比较低,这样其他模块被“拖累”的风险就较低。相应地,登陆界面被影响的概率也更低,我们得到的工程结果也更准确。


奈飞的登陆界面最终被选择用来试点 SwiftUI


关于项目目标,我希望 SwiftUI 能实现苹果宣称的开发优点,同时在产品和性能上不输原来 UIKit 实现的登陆界面。在此,我分别从两个方面透露一点细节:


  • 产品方面,我们希望 SwiftUI 重构的登陆界面不比原来的 UIKit 实现的登陆界面差就行。所以登陆、注册率不能下降;另外用户登陆之后,不会因为新的登陆界面别扭而影响观影体验,所以 App 的留存率和使用时间不能下降。


  • 工程方面,我们希望同样的模块用 SwiftUI 来实现,可以花更少的时间、写更少的代码量。同时登录界面的渲染和加载时间、崩溃率、流量使用、内存占用、电量消耗也是关注的重点。


在确定目标并估算好工期后,公司领导对这个项目十分认可。同时我确定了实施该项目的时间为 12 月份,因为这个月是美国公司的“淡季”——感恩节、圣诞节来临,大家都处于放松休假的状态。在此时开始 SwiftUI 的项目,不会耽误公司其他项目的进度,同时有充足的时间去调研。


2020 年 12 月初,我们正式开始了 SwiftUI 项目。

SwiftUI 的实际使用体验


先说优点,SwiftUI 的代码确实如苹果所说的一样:代码简洁易懂。


SwiftUI 重构的登陆界面的代码文件数量由 8 个减少到了 4 个,代码量由 350+行锐减到了 200+行(其中还有 40 行是用来显示预览)。


SwiftUI 声明式语法的易读性也得到了认可。重构的代码在审阅的时候,不仅有 iOS 的工程师,我还邀请了不同的 Android 和 Web 端工程师参与。不同背景的工程师对代码的理解都十分准确,毫无障碍;事后我跟他们的聊天,他们也盛赞声明式的语法、代码和预览界面一一对应的清晰直接。


另一个优点就是,SwiftUI 配合 Combine 可以非常高效地让界面动态响应数据源的变化。以前需要书写 GCD 来完成异步调用、主动调用方法来获取/更新数据、用 KVO 等方法来更新相关 UI 细节,这样的写法使得代码分散、整体逻辑琐碎、容易出错。现在完成这一切只需 Combine 配合 SwiftUI 通过几行代码来实现,整体架构立刻清晰明了不少,开发和维护成本大幅降低。


再说缺点,我对 SwiftUI 的不满主要有三点:


  • 糟糕的预览界面即时同步。在开发过程中,修改代码时对应的预览界面经常加载失败,需要手动重新尝试,重新尝试的等待时间又十分漫长;有时候,从网络端异步获取一些媒体资源也无法在预览界面中显示出来。这可能和奈飞 App 复杂的代码库有关,也可能是因为 SwiftUI 在 Swift & Objective-C 的混编环境下优化并没有做好。


  • 不稳定的 API。不得不说,现在调用很多 API,必须遵循很多官方都没有明说的“潜规则”。举个例子:

frame(minWidth:idealWidth:maxWidth:minHeight:idealHeight:maxHeight:alignment:)
复制代码

这个方法是用来规定 UI 控件布局和尺寸的。其中很多参数都有默认值,所以在调用时我们无需配置所有的参数值。试考虑以下调用方式:


frame(idealWidth: superViewWidth, maxWidth: 500)
复制代码


这种调用方式在 iPhone 上没有任何问题,而在 iPad 上可能会产生一些“意想不到”的效果。这是因为 min、ideal、max 这三个参数如果要明确赋值,则必须遵从从小到大的顺序(此条规则并没有在苹果的官方文件中明确说明);这里 superViewWidth 的大小在 iPhone 上一般不会超过 500,而在 iPad 上就很有可能超过 500 了——此时,idealWidth 的值大于 maxWidth 的值,UI 控件的尺寸和布局就会不尽如人意。


同时,调用多个 API 时,不同顺序亦会造成不同效果。我在开发中有时先调用 A 再调用 B 发现效果不仅如人意,debug 半天发现先调用 B 再调用 A 就解决了问题。


  • 控件和 API 匮乏。尽管 SwiftUI 在 iOS 14 时做了大幅改进:API 和控件数量都大幅提高,并且可以独立开发 App。然而,奈飞的 App 必须支持到 iOS 13——这也就意味着很多 SwiftUI 的新功能和改进无法使用。比如 lazyHStack、PageTabViewStyle,这使得原来只需一行就可实现的功能,需要多写几十行才能实现类似效果。当然我们可以针对 iOS 13 和 iOS 14 分别用不同的 SwiftUI 代码来实现,但这也增加了开发和维护成本。


相比于 UIKit 稳定的开发环境,SwiftUI 种种不良的开发体验绝对是目前大规模采用 SwiftUI 的“绊脚石”。


SwiftUI 天然适合模块化和响应式编程

总结


经过 A/B 测试之后,我们发现 SwiftUI 在产品指标上并没有造成下降。在工程指标上,相比于 UIKit,代码的数量和可读性都有了本质性地提升,开发效率却并没有那么好;在界面渲染和加载方面,SwiftUI 虽然总体略有下降(1%左右),但仔细观察数据,SwiftUI 在 iOS 14 和新机器上比在 iOS 13 和老机器上的性能表现要更好——这也就是说,随着苹果的更新,SwiftUI 的劣势会逐渐缩小;其他性能方面,SwiftUI 并没有展现出明显不同。


综上所述,我对 SwiftUI 的开发建议是:


  • 应该配合 Combine 和响应式编程思路来构建整体架构

  • 最好等 App 的最低支持版本为 iOS 14 时再去尝试

  • 不要直接在项目中开发 SwiftUI——更好的做法是先单独开一个项目,用 SwiftUI 大致实现需求的功能之后,再把相关代码整合进真正的 App 代码库


总之,我对 SwiftUI 长期看好,期待在 2021 年 WWDC 看到更多的改进,并在之后做更大规模的尝试。


发布于: 2021 年 05 月 02 日阅读数: 99
用户头像

故胤道长

关注

硅谷背包客 2017.10.17 加入

卡内基梅隆大学硕士毕业、常年居住于美国的增长黑客。 工作经历横跨Netflix、Quora、Amazon、Uber。Github 全美前十的 Swift 开源作者。 电子工业出版社2018年度优秀作家。著有《iOS 面试之道》一书。

评论

发布
暂无评论
SwiftUI @ Netflix:推动新技术落地是怎样一种体验?