Swift 5.4:用结果生成器来注解属性的教程

150 阅读2分钟

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]
}

当然,这只是一个非常小的变化,但如果你问我的话,这是一个非常受欢迎的变化。另外,结果生成器属性现在的行为与属性封装器属性的行为相同,这在一致性方面绝对是一个大的胜利。