神奇 Function Builder 造就 SwiftUI 独有 DSL
2023-10-14 21:21:54
我们终于来到了 SwiftUI 中所包含的最后一个重要特性:FunctionBuilder,之所以放在最后一篇中来讲,是因为它到目前为止仍旧是一个还未经过 Swift Evolution 评审的语言特性,苹果为了赶 WWDC 19 的时间点,因此先斩后奏赶鸭子上架了,因此本文讨…
Function Builder 的前世今生
SwiftUI 中的 Function Builder 脱胎于《A DSL for Builders》,作者是来自 Facebook 的好友 Chris Eidhof,相信很多开发者对 Chris 并不会感到陌生,他曾写过不少与 Swift 和 SwiftUI 相关的文章,其中影响力最大的一篇是《Building SwiftUI Views with Functions》,里面首次对 Function Builder 的构建、使用以及扩展做了详尽的。
了解 Function Builder,需要首先知道它的上下文(Context),顾名思义,上下文就是指能对执行上下文产生影响的一切因素,例如:函数(参数/返回值)、闭包(参数/返回值)、类型方法(Self/返回值)、类方法(Self/返回值)等。
而 Function Builder 就是一种接受一个或多个代码块作为参数,并执行这些代码块,最后返回一个特定结果的函数。
Function Builder 在 SwiftUI 中的使用
说了这么多,Function Builder 到底是怎么用呢?让我们先看这样一个例子:
struct MyHStack<Content: View>: View {
private let content: Content
init(@ViewBuilder content: () -> Content) {
self.content = content()
}
var body: some View {
HStack { content }
}
}
这是一个自定义的 Stack 视图,与 SwiftUI 的 HStack 唯一区别就是允许开发者在自定义的 Stack 视图中采用 ViewBuilder 构建 UI 组件,使用起来就像这样:
struct ContentView: View {
var body: some View {
MyHStack {
Text("Hello, World!")
Image(systemName: "moon.stars")
}
}
}
使用 ViewBuilder 来构建 UI 组件,使得整个代码看起来更加自然,更具可读性,此外 ViewBuilder 还可以用来解决一些问题,例如:
-
@Environment
和@EnvironmentObject
只能在 View 中使用,但有的時候需要在一个 View 的子视图中使用它们,此时可以使用 ViewBuilder 将子视图抽出来,单独放在一个 View 中,然后在该 View 中使用@Environment
和@EnvironmentObject
。 -
如果想把一个 View 作为另一个 View 的子视图,但又不想让该 View 受到父视图的影响,此时可以使用 ViewBuilder 将该 View 抽出来,单独放在一个 View 中,然后在该 View 中使用
@Environment(\.self)
获取父视图的环境,这样该 View 就可以不受父视图的影响了。
结语
Function Builder 是 SwiftUI 中一个非常强大的特性,它使得开发者可以使用更自然、更具可读性的代码来构建 UI 组件,此外它还可以用来解决一些问题,例如:@Environment
和 @EnvironmentObject
只能在 View 中使用,但有的時候需要在一个 View 的子视图中使用它们,此时可以使用 ViewBuilder 将子视图抽出来,单独放在一个 View 中,然后在该 View 中使用 @Environment
和 @EnvironmentObject
。