AI实践哪家强?来 AICon, 解锁技术前沿,探寻产业新机! 了解详情
写点什么

SwiftUI 真的适合大规模应用吗?三家初创公司的实践经验

  • 2024-10-16
    北京
  • 本文字数:4805 字

    阅读完需:约 16 分钟

大小:2.28M时长:13:16
SwiftUI真的适合大规模应用吗?三家初创公司的实践经验

导读:在 SwiftUI 的舞台上,其以现代化的声明式编程语法和卓越的性能赢得了业界的广泛赞誉。然而,作为一个仅发展了四年的新兴框架,SwiftUI 仍面临一些亟待解决的挑战。尤为突出的是,导航管理的不足成为限制其广泛应用的绊脚石。尽管 UIKit 的传统导航方式已相当成熟,但如何在保持 SwiftUI 现代特性的同时,有效融合这两种框架,成为众多开发者面临的难题。

 

如何借助 Coordinator 模式破解 SwiftUI 中的导航难题。我们将通过实战演示,利用 UIHostingController 和导航协议,构建一套既高效又灵活的应用导航系统。此方案旨在融合 UIKit 的经典优势与 SwiftUI 的创新特性,为开发者提供一套完美的解决方案。无论你是 SwiftUI 的新手还是资深专家,本文都将为你奉上实用的技巧和深刻的洞见,助你跨越复杂应用开发中的导航难关。加入我们,一同探索如何在 SwiftUI 与 UIKit 之间搭建桥梁,解锁更多强大的功能潜力,让你的应用导航更加流畅、高效!

 

今天,我将与大家分享我在三家初创公司中运用 SwiftUI 的实践经验,并深入探讨我是如何克服那些阻碍你全面采用 SwiftUI 的关键挑战的。

 


本文改编自我于 2023 年 6 月在 Monzo 伦敦办公室举办的 NSLondon 演讲。

 

SwiftUI 的演进历程

 

自 SwiftUI 问世以来,我有幸一直是其主要用户。

 

作为 SwiftUI 的忠实拥趸,我亲眼见证了它的成长与发展。回溯至 2019 年,当 SwiftUI 的初版测试版横空出世时,我正投身于一个名为 Patcher 的副业初创项目之中,该项目旨在成为汽车维修领域的 Uber。如同许多初创团队的工程师一样,我们怀揣着满腔热情,决定在赢得首批用户青睐之前,先全力以赴地完善所有功能。

 

Patcher 应用功能繁多,涵盖了地图导航、新手引导、用户资料管理、工作请求处理、支付系统、维修流程跟踪等各个环节,甚至还包括了一个专为维修技师设计的配套应用。然而,这一项目的复杂性不言而喻,而那时的 SwiftUI,尤其是在 2019 年底至 2020 年初的阶段,显然还难以驾驭如此庞大的系统。

 

初期的 UIKit 与 SwiftUI 之间的互操作性并不理想,状态管理也成为了一项挑战,尤其是在整合像 Google Maps SDK(当时 SwiftUI 中的 MapView 尚未问世)和摄像头功能时,这些问题尤为凸显。更令人沮丧的是,SwiftUI 1.0 版本的导航功能几乎形同虚设,迫使我们不得不大量依赖模态视图来实现应用内的导航。

 

时间推移至 2020 年末,我参与了 Carbn 的创立,这是一家旨在引导人们培养更环保生活方式并减少碳足迹的初创企业。幸运的是,此时 iOS 14 已经发布,SwiftUI 也迎来了它的黄金时期。随着 @StateObject、惰性堆栈(lazy stacks)、ScrollViewReader 等强大工具的加入,以及我个人极为偏爱的 matchedGeometryEffect 效果的引入,SwiftUI 的功能与性能得到了显著提升。但更为重要的是,开发者们开始逐渐掌握如何利用 SwiftUI 构建出既合理又高效的应用程序。

 

现在,作为 Gener8 公司的移动工程负责人,我带领团队致力于帮助用户掌握并利用自己的数据创造价值。我们非常幸运地能够专注于 iOS 15 及以上版本的开发,这使得我们能够充分利用材质效果、可刷新视图、任务修饰符以及 Markdown 渲染等先进功能。

 

可以说,SwiftUI 已经全面成熟,从四年前的一个实验性工具,成长为能够支撑起严肃商业项目的强大 UI 框架。

 

它真的适合在生产环境中大展拳脚吗?

 

简而言之,如果你在生产环境中选择使用 SwiftUI,那么它绝对能够胜任!

 

回顾过去,Swift 在实现 ABI(应用程序二进制接口)稳定性之前,许多 Objective-C 开发者曾对 Swift 能否应对大型项目持怀疑态度。同样地,到了 2030 年,我们或许还会听到有人坚持推崇 UIKit(尽管我尚未见到有人仍在使用 Storyboard)。

 

接下来,我将简要分析 SwiftUI 的优势、存在的不足,以及为何一些工程师尚未完全全面转向 SwiftUI。

 

SwiftUI

优势

 

关于 SwiftUI 的优点,我不再一一赘述,仅简要提及几点核心优势。它速度快、采用声明式编程模式、具备高度响应性,并内置了单向数据流,让开发者能够轻松驾驭数据流向。无疑,SwiftUI 代表着未来的发展方向。

不足

 

当然,SwiftUI 也非尽善尽美。其导航功能稳定性一直是个问题,对于传统 UIKit 框架中的 AV(音频视频)、Camera(相机)和 Maps(地图,尤其是 iOS 17 之前的版本)等功能的支持较为有限。由于 SwiftUI 尚处于不断完善之中,有时开发者可能仍需借助 UIKit 来实现特定功能。此外,SwiftUI 的渲染引擎背后是 CoreAnimation、UIKit 和 Metal 的复杂交织,这种 “幕后魔法” 使得精确的性能调优变得更具挑战性。

 

难题

 

坦率而言,苹果似乎更倾向于将焦点放在单视图或主从结构上,对其他类型的应用架构则略显忽视。与所有新兴框架一样,SwiftUI 所依赖的操作系统版本不断变化,这意味着开发者需要在代码中频繁使用 if #available 语句来确保兼容最新功能。此外,SwiftUI 的状态管理机制与现有的 UIKit 代码体系存在较大差异,两者之间的无缝融合仍是一个待解的难题。

 

SwiftUI 虽然备受赞誉,但仍有其不足之处。作为一个仅诞生四年的新兴框架,某些缺陷在预料之中,然而,有一个核心问题显著地限制了它的广泛应用:

 

导航难题亟待解决

 

导航问题无疑是开发者在全面拥抱 SwiftUI 时遇到的首要障碍。特别是对于构建大型、复杂的应用程序而言,目前还缺乏一个理想的导航解决方案。虽然利用应用数据状态来控制导航逻辑在小规模应用中颇为有效,但尝试将这种方法扩展到大型项目时,其复杂性和工作量会急剧增加。开发者不应被迫去记忆整个应用的状态变化,以此推断出应该展示哪个界面。

 

问题的根源在于……

 

“大型视图控制器” 问题重现江湖

 

为了更深入地理解这一挑战,我们来看看苹果在 iOS 16 中对 SwiftUI 导航模式的改进尝试:

 

NavigationStackNavigationLink.navigationDestination.sheetNavigationSplitView

 

这些功能都紧密集成在 SwiftUI 的视图体系中,允许视图根据用户的交互行为或应用的状态变化来动态决定哪些子视图应该被呈现。

 

这迫使开发者不得不将视图与导航逻辑紧密绑定在一起,极大地挑战了代码的可测试性,也违背了工程开发的最佳实践原则。实际上,iOS 开发界的工程师们才刚刚挣脱出这种不良习惯的束缚。回想起过去,使用字符串类型的 segue、在 viewDidLoad() 方法中直接调用 URLSession、以及将整个应用逻辑堆砌在单个 Main.storyboard 文件中的日子,简直如同梦魇般让人心有余悸。

 

对于初涉 iOS 开发领域的你,若想深入了解 “大型视图控制器” 综合症的根源与影响,Paul Hudson 的这篇教程无疑是极佳的入门指南。它不仅深刻剖析了因关注点混乱导致的种种问题,还系统介绍了 UIKit 的最佳实践方法,为开发者指明了优化代码结构的路径。

 

导航逻辑的抽象化

 

我们已经明确了问题的症结所在:SwiftUI 尚不支持将导航逻辑进行有效的抽象化处理,这给大型工程团队在协作开发复杂应用时带来了不小的困扰。

 

但好消息是,解决方案并非遥不可及,它其实就隐藏在我们日常的编码实践中。

 


Coordinator 模式

 

这一模式,有时也被称为 Router 模式或 Navigator 模式,其核心思想高度一致:即将导航逻辑进行封装,实现与视图层的解耦。

 

我个人倾向于在 AppDelegateSceneDelegate 中引入一个 AppCoordinator 来实施此模式。该 Coordinator 作为整个应用的导航中枢,负责全局的导航管理,并可以根据需要创建多个子 Coordinator 来分别处理不同的业务逻辑流程。这些子 Coordinator 又可以进一步细化,管理更为具体的导航逻辑,从而形成一个层次分明、结构清晰的导航管理体系。

 


使用 Coordinator 模式的基础应用架构

 

Coordinator 的协议设计相对简洁明了:

 


Coordinator.swift

 

在 Coordinator 的设计中,Route 通常被定义为一个枚举类型,它列举了在该 Coordinator 所负责的导航流程中可能出现的各个界面。整个应用程序的导航逻辑都被巧妙地封装在 Coordinator 的 navigate(to:) 方法中。

 

尽管这种方法在 UIKit 框架中颇为常见,但接下来我将详细说明如何对其进行调整,以实现与 SwiftUI 框架的完全兼容。为此,我们只需引入两个额外的关键组件:

 

UIHostingController

 

UIHostingController 扮演了一个桥梁的角色,它将 SwiftUI 的上下文包裹在 UIViewController 之中,从而实现了这两种 UI 框架之间的无缝对接。

 

导航协议

 

为了进一步提升应用的灵活性和可维护性,我们将引入两个新的协议。这两个协议旨在抽象化 UINavigationController 和 UITabBarController 的功能,这两者都是构建复杂 UIKit 应用的基石。这样一来,无论你是否有 UIKit 的开发背景,都能轻松理解和应用你应用的导航结构。对于熟悉 UIKit 的开发者而言,这样的设计更是能够让他们迅速上手,并充分利用他们在 UIKit 中的经验来优化 SwiftUI 应用的导航体验。

 


通过 Coordinator 模式构建的导航架构

 

NavigationContext

 

此协议明确了我们对导航功能的基本需求:即能够展示和隐藏 SwiftUI 视图,同时将呈现逻辑与视图代码清晰分离。

 


NavigationContext.swift

 

在这个文档中,我们定义了一系列呈现函数,这些函数接收一个泛型视图作为参数,并实现了所有核心的导航操作,如推送、弹出视图,呈现和关闭视图,以及在导航结构的根位置创建初始视图。

 

协议的具体实现则是通过继承自 UINavigationController 的子类完成的:

 


MyNavController.swift

 

在这个文档中,你会发现实现过程与标准的 UIKit 导航方法非常相似,但多了一步操作 —— 即将 SwiftUI 视图包裹在 UIHostingController 中,以实现两者之间的无缝衔接。

 

接下来,我们可以轻松地为第一个 Coordinator 的 navigate(to:) 方法填充实现逻辑:

 


MyCoordinator.swift

 

NavigationRoot

 

此协议则是对 UITabBarController 功能的抽象,通常你的应用中仅会有一个这样的控制器,由 AppCoordinator 负责管理。

 


NavigationRoot.swift

 

尽管此部分不直接涉及 SwiftUI,但它负责管理多个导航上下文,并允许用户通过标签栏在不同上下文之间切换。此外,还提供了在标签栏控制器上模态展示上下文的功能,这在处理登录认证等场景时尤为实用。

 

拓展功能

 

在成功整合了所有主要构建块之后,我们不仅能够利用拥有 16 年历史的 Cocoa Touch API 来开发 SwiftUI 应用,还可以通过进一步子类化 UIHostingController 来增强功能。这样,我们可以:

 

  • 在每个视图上实现个性化的样式,无需依赖 UIAppearance API

  • 利用 UIViewController 的生命周期事件,在不同 NavigationContexts 之间传递状态

 

以下是一个基本实现的示例:

 


MyHostingController.swift

 

这一实现将引导我们创建一个更加复杂的 navigate(to:) 方法:

 


MyCoordinator.swift

 

通过利用视图的生命周期事件,在父视图上动态地显示和隐藏覆盖层。最终,我们展示了如何通过标准的 Coordinator 模式实现 UIKit 与 SwiftUI 之间的无缝互操作性,并以展示 SFSafariViewController 为例进行了演示。

 

结论

 

虽然 Coordinator 模式并非构建复杂 SwiftUI 应用的唯一途径,但它无疑是一个高效且实用的选择。当然,你也可以根据需求选择基于状态的范式,或者如果你的目标平台是 iOS 16 及以上版本,还可以考虑使用更新的导航 API,甚至尝试采用 The Composable Architecture 等先进架构。

 

这些不同方案的共同之处在于,它们都在不断推动技术发展。通过采用 Coordinator 模式,你可以在享受 SwiftUI 带来的响应式 UI 和快速开发优势的同时,充分利用 UIKit 在导航和定制方面的强大功能。此外,你还可以轻松实现即插即用的互操作性,几乎无需担心状态管理的问题。如果你尚未全面转向 SwiftUI,那么现在就是利用这些经过时间考验的范式的好时机,让我们从今天开始,迈向更加高效的开发之路。

 

作者简介

 

Jacob,现任伦敦一家初创公司的首席 iOS 工程师。

 

原文链接:

 

https://jacobbartlett.substack.com/p/swiftui-apps-at-scale

 

声明:本文为 InfoQ 翻译整理,未经许可禁止转载。

2024-10-16 16:1310207

评论

发布
暂无评论
发现更多内容

给需要关心安全的技术人员的一些建议

鉴释

网络安全 安全

阿里内部最新出炉“SpringCloudAlibaba笔记”号称微服务界的里程碑!

Java 编程 架构 微服务 计算机

真的强!来自扫地僧总结的39W字上千道Java一线大厂面试题手册,成功助我拿下蚂蚁金服offer!

钟奕礼

Java 编程 程序员 架构 面试

抓住“开源盛世“,这个工具你必须了解一下

鉴释

开源 代码安全

彩印图文版《Elasticsearch实战》文档,阿里内部共享,堪称精品

白亦杨

Java 编程 程序员 架构师 计算机

阿里秋招面试必问的几个知识点:Spring+Redis+MySQL+HashMap+多线程,不看我真的怕你后悔

Java 程序员 架构 面试 计算机

Linkflow签约未卡VETRESKA,精细化运营赋能品牌成功破圈,开启种草新模式

Linkflow

为什么“内存管理”漏洞值得你的绝对关注!

鉴释

代码审查 内存 代码

提升源代码安全管控,从源头保护敏感数据

鉴释

数据安全

因聚而生 | 图扑受邀参加“生态融合,智创未来”大会

一只数据鲸鱼

数据可视化 数字孪生 智慧工业 智能制造

iOS面试·一个iOS程序员的BAT面试全记录(内含百度+网易+阿里面试真题)

iOSer

ios 面试 iOS 知识体系

C/C++Linux服务器开发高级架构师/Linux后台开发架构师丨高级进阶

Linux服务器开发

架构师 Linux服务器开发 Linux后台开发 后台开发架构师 服务器开发架构师

ES本地debug详解

泽睿

ES 搜索引擎;

耗时半年,堪称奇迹!阿里架构师整合出258W字Java全栈面试题

钟奕礼

Java 程序员 架构 面试 计算机

5000页?一份字节跳动Java面试全解手册发布!瞬间登顶各大搜索栏

钟奕礼

Java 编程 程序员 架构 面试

MES、ERP和低代码下的智慧工厂

优秀

低代码 ERP mes

赖建新:关于静态代码分析的问与答

鉴释

静态代码分析

真香!180页100+题15W+字解析的《Java高级面试指南》,果断收下

Java 编程 程序员 架构师

如何利用FL Studio中文版做出失真效果

懒得勤快

新时代程序员都用什么写代码?

程序员鱼皮

Java Python 大前端 Web 开发工具

漏洞非小事,金融服务机构如何对抗代码缺陷?

鉴释

金融科技 代码安全检测

Kubernetes实战:高可用集群的搭建和部署

华为云开发者联盟

Kubernetes 高可用 集群 高可用集群 apiserver

不保护数据的代价!

鉴释

数据 数据安全

字节大牛的1850页Leetcode刷题笔记外泄!用实力折服众人

进击的王小二

Java 面试 算法 LeetCode

从零开始学习3D可视化之数据对接(2)

ThingJS数字孪生引擎

大前端 数据 可视化 数字孪生

IDC报告深度解析:谁将领跑中国RPA市场?

ToB行业头条

RPA IDC

把凭据嵌入源代码,来看看你的代码里有这样的操作吗?

鉴释

代码安全

鉴释获得 A+ 轮融资,将加强对新技术的投资并扩展中国团队规模

鉴释

企业融资 创业公司

“Talk is cheap, show me the code”你一行代码有多少漏洞?

鉴释

代码质量 静态代码分析

即时通信 IM 产品怎么选? 本文超详细解说,马住!

腾讯云音视频

阿里集团业务驱动的升级 —— 聊一聊Dubbo 3.0 的演进思路

阿里巴巴中间件

云计算 阿里云 云原生 dubbo 中间件

SwiftUI真的适合大规模应用吗?三家初创公司的实践经验_Android/iOS_Jacob_InfoQ精选文章