盼望着,盼望着,东风来了,秋天的脚步近了。随着 Xcode 16 的即将发布,Xcode 最低 Debug 版本也被限制到了 iOS 13+。运气好的一部分 iOSer 终于可以在工程里把 minimum deployment target 设置到 iOS 13,在 iOS 13 发布 5 年后,终于迎来了 iOS 13 SDK。
不同于以往,5 年前的 WWDC 19 发布了众多的次时代炫酷框架。并且得益于 Swift @backDeployed
等相关特性,近五年新发布的一些功能,诸如 Concurrency
、viewIsAppearing
,也能在 iOS 13 发布之后也能陆续向前被兼容。
本文将会梳理截止目前(2024 年 8 月),升级到 iOS 13 SDK 后,作为一个普通的 iOS 开发者,终于能够用上的实用框架和功能简介。
SwiftUI
不必说,SwiftUI 算是 WWDC 19 上没有之一的最明星的框架了。5 年来相信大家对它也有所耳闻。
不过令人遗憾的是,SwiftUI 是随着系统发布,并且与系统绑定的。因此历代系统中有的一些 SwiftUI bug 只能通过升级系统的方式来解决。并且每年 SwiftUI 框架中新发布的功能,也只能在新系统上用上。
除此之外,一些比较基础的能力,如惰性布局容器 LazyV/HStack
和 @StateObject
,在 iOS 14 中才提供,而导航 API 在 iOS 16 中有一次大的重构(NavigationView
-> NavigationStack
)。其实比较建议在更高版本系统上再开始使用 SwiftUI(如 iOS 15/16+)。在低版本系统中尽量还是使用与 UIKit 桥接的方式,在个别简单控件中桥接使用 SwiftUI。
资料推荐:
- 入门资料:
- SwiftUI 官方教程:官方提供的互动式教程,可以作为入门的不二之选。
- 网页使用了
Vue
框架,也许是声明式框架的致敬
- 网页使用了
- SwiftUI Cheat Sheet:SwiftUI 与 UIKit 控件对照列表清单、控件基础使用方法。
- 一些适合 SwiftUI 初学者的教程 | 肘子的 Swift 记事本:其他的一些基础教程
- SwiftUI 官方教程:官方提供的互动式教程,可以作为入门的不二之选。
- 进阶资料:
- SwiftUI | 肘子的 Swift 记事本:肘子哥写过的关于 SwiftUI 的高质量踩坑总结博客,不仅教"术"还传"道",在入门之后强烈推荐。
Combine
Combine 是与 SwiftUI 一同发布的另一个强大框架,是一个类似于 RxSwift 的 Reactive 框架。
Combine 比 RxSwift 有以下优势:
- 性能更好:据测试,Combine 比 RxSwift 的综合性能提升了约 30%
- 深度集成:得益于是系统层面的框架,Combine 与其他系统框架有更深度的集成,比如 SwiftUI 的部分 API,可以直接与 Combine 集成
- 包体积:在全面切到 Combine 之后,也可以弃用 RxSwift,减少包体积
- Debug 更直观:作为系统库,可以直接隐藏堆栈,减少无效堆栈的展示
- 依赖方便:在 Demo 中使用 Reactive 功能时,可以考虑直接使用 Combine 而不用单独为项目引入 RxSwift 了
Combine 与 RxSwift 的不同:
- 规范不同:RxSwift 实现的是 ReactiveX 规范,Combine 实现的是 Reactive Stream 规范
- Back-Pressure:Combine 独有的功能,可以设置 subscriber 收到的流速。
- 实践中比较大的不同:
subscribe
之后,RxSwift 如果不持有Disposable
,可以正常继续订阅;Combinesink
之后,必须持有AnyCancellable
,否则订阅就会立刻失效(类似 KVO)。
需要注意的是,Apple 在 WWDC 23 上发布了 Observation框架,在绝大多数 SwiftUI 场景已经可以不用 Combine 了。不过遗憾的是 Observation 要求 iOS 17+。
资料推荐:
- RxSwift to Apple's Combine Cheat Sheet:RxSwift 到 Combine 的概念和方法对照清单
Concurrency
3 年前的 WWDC 21 上,随着 Swift 5.5 的发布,async/await
语法终于来到了 Swift 。并且虽然框架发布之初只支持 iOS 15+,但是在框架正式发布的最后时刻向前兼容到了 iOS 13+。
但是 Swift Concurrency 并不仅仅是 async/await
语法,并不仅仅解决了回调地狱
的问题,还解决了数据竞争(Actor/Sendable)
和**结构化**并发(Task/TaskGroup)
的问题。
数据竞争可以帮助我们摆脱麻烦的锁和线程等传统资源竞争处理方式,类似 Rust 的从编译期避免各类数据竞争问题;结构化并发则可以帮助我们更高效优雅地开启并发任务。
资料推荐:
- 入门资料(选一个系列看就好):
- Meet Swift Concurrency - Discover - Apple Developer:WWDC 21 官方介绍合集
- 【老司机精选】认识 Swift 中的异步与并发 - 掘金:WWDC 介绍中文版
- Swift 新并发框架之 async/await - 掘金:共四篇文章,深入浅出,比较推荐
- Swift 并发初步 | OneV's Den:并发入门简介
- Async await in Swift explained with code examples - SwiftLee:使用样例
- 进阶资料:
- Emerge Tools Blog | Async await in Swift: The Full Toolkit:和并发相关的工具栈介绍
- apple/swift-async-algorithms: Async Algorithms for Swift:建议引入工程的并发相关基础工具,类似于 Swift Algorithms之于 Swift。提供了一些常用操作符,以及异步通信通道(AsyncChannel)等等基础工具。
- Swift Concurrency -- Things They Don't Tell You:深入理解并发中一些需要注意的细节
- Swift 6 适配的一些体会以及对现状的小吐槽 | OneV's Den:Swift 6 适配并发检查
Macro
去年的 WWDC 23 上,Swift 5.9 引入了一个重大更新:Swift 宏,并且向前兼容到了 iOS 13+。与 C 宏最大的不同是,C 宏只是简单的字符串替换,而 Swift 宏在设计时就考虑了以下几个原则:
- Distinctive use sites:一眼就能看出是不是一个宏(必须带上
#
或@
) - Complete, type-checked, validated:宏的入参和结果都会进行类型检查
- Inserted in predictable ways:宏只能添加代码,不能改变或删除
- Macros are not magic Macros:可以展开宏、给宏打断点、编译失败时,可以看到具体错误位置
最早,必须通过 SPM 使用 Macro,后来也有人研究出可以通过 CocoaPods 使用的方式,参考:Distributing a Swift Macro using CocoaPods
资料推荐:
New in UIKit
UIKit 这些年每年都有新的 API,并且有的 API 向前兼容到了 iOS 13+,列举一些比较有用的:
- viewIsAppearing:在
viewWillAppear
之后,布局完成之后(traits 和 geometry 已经准确了),viewWillLayoutSubviews
之前,适合布局的绝佳时机。(WWDC 23 发布, Apple 藏了 4 年的 Private API,终于公开了,向前兼容到 iOS 13) - UICollectionView:Compositonal Layout & Diffable Data Source
- UITableView insetGrouped style
- UIMenu / UIContextMenuInteraction:可以考虑大量使用更现代方便的
Menu
组件替换ActionSheet
组件。 - UITraitCollection:系统级支持了 DarkMode、通过
UITraitCollection.current
获取 screenScale 而非废弃的UIScreen.main
Refs: iOS 13: Notable UIKit Additions | Swiftjective-C
Other Frameworks
- Core Haptics:支持更精细的振动,可以像播放音乐一样完全自定义振动
- SF Symbol:系统内置图标库
- CryptoKit:生成哈希值、加解密数据、数字签名等等,可以参考介绍文章