WWDC21 即将开始,我想延续我在 2019 年开始的传统,并分享我对今年大会的一些最大的希望和梦想。
请注意,这些实际上不是预测,也不是基于任何类型的内幕信息。这只是我与您分享我个人的一些与 Swift 相关的 WWDC 梦想。
强大的 SwiftUI 自定义
我非常喜欢 SwiftUI(非常喜欢,以至于我想将它移植到网络上),但这并不意味着它是完美的。事实上,在这一点上它只有两年的历史,它仍然是一个非常年轻的框架,还没有像 UIKit 和 AppKit 这样的工具那样功能齐全、灵活和强大。
今年我希望看到的关键改进之一——这将释放很多额外的功能和灵活性——是让 Apple 向框架附带的整个系统视图套件添加适当的、完全烘焙的自定义 API .
例如,就像我们在“封装 SwiftUI 视图样式”中看到的那样,当涉及到 Button 视图的样式时,ButtonStyle 协议已经使我们能够执行非常自定义、细粒度的自定义:
struct ActionButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.foregroundColor(.white)
.font(Font.body.bold())
.padding(10)
.padding(.horizontal, 20)
.background(Color.blue)
.cornerRadius(10)
}
}
使用上述协议定义的样式如此强大的原因在于它们可以立即应用于整个视图层次结构——从而可以非常巧妙地将应用程序的样式和主题代码与包含在每个单独视图中的特定逻辑分开。事实上,如果我们愿意,我们甚至可以简单地通过执行以下操作来为整个基于 SwiftUI 的应用程序中的所有按钮设置样式:
@main struct MyApp: App {
var body: some Scene {
WindowGroup {
RootView().buttonStyle(ActionButtonStyle())
}
}
}
然而,虽然 SwiftUI 已经附带了许多其他样式协议,它们的工作方式与 ButtonStyle 完全相同,但其中许多目前尚无法供我们第三方开发人员实现。以 NavigationViewStyle 协议为例。如果我们通过在 Xcode 中通过命令单击来查看它的公共定义,我们将看到的是:
public protocol NavigationViewStyle {
}
同样的事情也适用于其他类似的协议——包括 ListStyle、MenuButtonStyle、PickerStyle 等等。因此,我希望 Apple 开放这些协议,以便我们能够或多或少地为任何内置 SwiftUI 视图编写自定义样式,而不仅仅是为一些选择的视图,例如 Button 和 Label。我认为这可以解决许多开发人员(包括我自己)在需要更多自定义 UI 的应用程序中采用 SwiftUI 时所面临的许多与样式相关的问题。
例如,上述类型的自定义 API 可以使我们能够设置导航和标签栏的样式,(最终)能够删除列表单元格分隔符,并执行 UIKit 和 AppKit 使超级简单的其他类型的常见调整,但目前 SwiftUI几乎不可能(不诉诸某种形式的 UIAppearance 或子视图黑客)。
我认为 SwiftUI 在它支持的视图类型方面已经有相当广泛的覆盖面,所以(至少从我的角度来看)苹果今年转而专注于深度是很有意义的——使SwiftUI 已经提供了更加灵活、强大和可定制的视图。
Async/await all the things!
由于并发是 Swift 5.5 的一个重点(一旦我有机会使用它来编写正确的生产代码,我将更详细地介绍它),我很想看到 Apple 更新许多异步 API作为其 SDK 的一部分提供,以充分利用 async/await 等功能。
例如,想象一下能够像这样执行基于 URLSession 的网络调用:
let response = try await URLSession.shared.dataTask(for: url)
或者像这样请求推送通知权限:
let center = UNUserNotificationCenter.current()
let isAuthorized = try await center.requestAuthorization()
虽然Combine 已经使我们能够以非常强大的方式执行多种异步任务,但如果Apple 要完全接受Swift 新的一流并发功能,我认为这既可以作为社区效仿的很好的例子,也可以使它我们也更容易在我们自己的代码中采用这些功能。
此外,这些新 API 很可能纯粹是对现有 API 的补充,这意味着(就像引入 Combine 时一样)我们可以按照自己的节奏逐个迁移到它们。
交互式小部件
要说 iOS 14 对 WidgetKit 的引入已经证明是成功的几乎是轻描淡写——新的主屏幕小部件得到了非常广泛的采用,不仅在开发人员和技术爱好者中,而且在更广泛的 iOS 用户群中(在很大程度上感谢 Widgetsmith 创作者 David Smith 的出色工作,我很高兴在播客上与他交谈一段时间)。
然而,就目前的形式而言,小部件在它们可以接受的用户交互类型方面非常有限——与宿主应用程序的深层链接是实现自定义交互逻辑的唯一真正方式。现在,我完全理解苹果为什么做出这个决定了。毕竟,就像 Eliza Block 去年在播客上做客时所解释的那样,小部件的 UI 实际上并不是一直在主屏幕上运行,而是由系统根据存储在磁盘上的序列化快照来呈现,主要是出于性能和能源效率的原因。
因此,如果系统本质上将所有小部件呈现为预先计算的完全静态的视图层次结构(由小部件的支持 TimelineProvider),Apple 如何使我们能够在该上下文中编写自定义交互代码,而不从根本上改变小部件的工作方式?
想到的一个想法是可以引入某种形式的基于事件的消息传递系统,这将使给定的小部件的时间线条目视图能够触发自定义事件,例如使用类似内置 EventButton 之类的东西:
struct ArticleWidgetEntryView: View {
var entry: ArticleEntry
var body: some View {
VStack(alignment: .leading, spacing: 5) {
Text(entry.article.title)
.bold()
Text(entry.article.description)
.foregroundColor(.secondary)
.font(.footnote)
EventButton(
systemImage: "heart.fill",
event: ArticleWidget.Event.toggleFavorite
)
}
.padding()
}
}
由于上述不涉及执行任何视图级代码来响应用户交互,它仍然会让系统保持对所有小部件 UI 的渲染和生命周期的完全控制。
因为 WidgetKit 是 Swift(UI)-only,所以上面的 Event 类型很可能会被主 Widget 定义和它的 TimelineProvider 以完全类型安全的方式引用——而不必传递原始字符串或 userInfo-风格字典周围。
例如,也许 TimelineProvider 协议(或其专门版本)可以获得一个新方法,该方法将传递任何触发的事件(以及触发它的条目),这反过来又会让我们运行完全自定义的代码作为回应,同时仍然使系统能够继续使用其基于快照的渲染策略。
坚如磐石的工具
尽管 Swift 工具的整体质量以及它集成到 Xcode 的方式自该语言首次引入以来肯定有所改善,但它仍然是 Swift 整体上最显着的缺点之一。到 2021 年,自动完成完全停止工作、语法突出显示消失以及在编译失败时显示模糊错误消息的情况仍然很常见——即使在相对简单的项目中也是如此。
我意识到这些不是容易解决的问题,尤其是考虑到 Swift 的整体复杂性和非常快速的进化,但如果我只能从这个梦想列表中挑选一个项目,那就是这个。 Swift、UIKit、SwiftUI 以及 Apple 的其他框架和 SDK 有很多值得喜欢的地方,尽管存在所有缺陷,但我认为 Xcode 总体而言实际上是一个非常棒的开发环境——我真的希望基本的编辑体验将提升到我对 Apple 产品所期望的非常高的质量水平。
这并不是说 Swift 的所有工具都有缺陷。以 Swift 包管理器为例——总的来说,它是迄今为止我用过的最稳定、最易于使用的依赖管理系统(我并不是说这是对任何其他包管理器的侮辱)那里)。基本上,在使用 SwiftPM 时,依赖项管理基本上已成为一个已解决的问题,至少对我和与我一起工作的团队而言。它快速、可靠且功能强大。对于 Xcode 的新构建系统,以及为 Apple 平台开发应用程序的整体体验的许多其他部分,现在也可以说同样的事情。
所以,我希望一些粗糙的边缘被平滑,我相信我们总有一天会到达那里。让我们看看 Xcode 13 的发布日是否会在那一天。