Swift 5.4 中的新内容: 结果生成器属性现在可以直接附加到基于闭合的属性上,这可以让我们更容易编写诸如自定义SwiftUI容器以及其他利用Swift结果生成器功能的代码。
让我们先看看"创建自定义 SwiftUI 容器视图 "中的一个例子,在这个例子中,我们建立了自己的 SwiftUI 容器视图,在ScrollView 中渲染了一个水平堆叠的子视图。
由于我们希望在创建该容器视图的实例时能够使用SwiftUI DSL 的全部功能,因此我们给了它一个初始化器,该初始化器接收一个标有 SwiftUI@ViewBuilder 属性的闭包,这反过来又让我们以与使用 SwiftUI 所提供的内置容器完全相同的方式使用它。
struct Carousel<Content: View>: View {
var content: () -> Content
init(@ViewBuilder content: @escaping () -> Content) {
self.content = content
}
var body: some View {
ScrollView(.horizontal) {
HStack(content: content).padding()
}
}
}
不过,从 Swift 5.4 开始,我们不再需要那个明确的初始化器,而是可以直接用@ViewBuilder 属性标记我们的content 属性本身--像这样:
struct Carousel<Content: View>: View {
@ViewBuilder var content: () -> Content
var body: some View {
ScrollView(.horizontal) {
HStack(content: content).padding()
}
}
}
真的很好!即使有了上述变化,我们也可以像以前一样继续使用我们的Carousel 视图,这要感谢Swift的成员初始化器功能。
这一变化也适用于我们定义的任何自定义结果构建器。例如,在"深入了解 Swift 的结果构建器 "中,我们使用一个名为SettingsBuilder 的自定义结果构建器构建了一个SettingsGroup 类型。在 Swift 5.4 之前,我们不得不再次手动实现该类型的初始化器,以便能够在其settings 闭包中使用我们的结果构建器。
struct SettingsGroup {
var name: String
var settings: () -> [Setting]
init(name: String,
@SettingsBuilder settings: () -> [Setting]) {
self.name = name
self.settings = settings
}
}
但现在我们可以重构上述类型,使其看起来就像这样:
struct SettingsGroup {
var name: String
@SettingsBuilder var settings: () -> [Setting]
}
当然,这只是一个非常小的变化,但如果你问我的话,这是一个非常受欢迎的变化。另外,结果生成器属性现在的行为与属性封装器属性的行为相同,这在一致性方面绝对是一个大的胜利。