SwiftUI and Swift 5.1 New Features (4) Apple fait accompli? Function Builder to create a DSL SwiftUI

We begin by following this example look at Swift 5.1 new features have been studied in SwiftUI in: some SwiftUI and Swift 5.1 New Features (1) opaque return type Opaque the Result Type , as well as @Stateand @Bindingbehind @propertyDelegate SwiftUI and Swift 5.1 New Features (2) Properties Delegates agent Property , and @dynamicMemberLookup SwiftUI and Swift 5.1 new Features (3) Key Path Member Lookup

struct SlideViewer: View {
  @State private var isEditing = false
  @Binding var slide: Slide

  var body: some View {
    VStack {
      Text("Slide #\(slide.number)")
      if isEditing {
        TextFiled($slide.title)
      }
    }
  }
}
复制代码

We finally came to the last important characteristic SwiftUI contained: FunctionBuilder, put the last one in terms of the reason is because it is so far still has not passed a language feature Swift Evolution review, in order to catch Apple WWDC 19 point in time, and therefore still dealing with the spot, so the details discussed in this article may change in the future, but due to the impending release of iOS 13, should not reinvent the wheel.

1. SwiftUI DSL needs

We need to carefully analyze the syntax of the above DSL code:

  1. Degenerate from the expression: possible unnecessary commas, return, brackets and the like.
  2. It supports simple logic control, if such control statements.
  3. Strongly typed: some Viewrepresents a composite of strongly typed, when View is changed, the composite of strongly typed help make View diff optimization.
  4. Swift existing syntax and do not conflict.

2. to understand @_functionBuilder by ViewBuilder

Like @propertyDelegateused to modify Statethe same, @_functionBuilderused to decorate ViewBuilder, there is also ViewBuildernothing but a compiler will use it, and there are certain types of requirements for the methods it contains. So ViewBuilderwhere is it? In fact, the final closure of the parameters of the various types of containers to VStackan example:

// 定义
struct VStack<Content> where Content : View {
  init(alignment: HorizontalAlignment = .center, spacing: Length? = nil,
  @ViewBuilder content: () -> Content)
	
}

// 使用
struct ContentView : View {
  var body: some View {
    VStack(alignment: .leading) {
      Text("Hello, World")
      Text("Leon Lu")
    }
  }
}
复制代码

In the above example, we can see how the tile SwiftUI properties comprising in one container type; closure function definition, we see the modified ViewBuidler. It is not difficult to infer, in order to be able compiled, ViewBuidler for the closure of the code at compile time "move the hands and feet", then this is how to do it? The key method ViewBuilder view of:

static func buildBlock() -> EmptyView
static func buildBlock<Content>(Content) -> Content
static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>
static func buildBlock<C0, C1, C2>(C0, C1, C2) -> TupleView<(C0, C1, C2)>
static func buildBlock<C0, C1, C2, C3>(C0, C1, C2, C3) -> TupleView<(C0, C1, C2, C3)>
static func buildBlock<C0, C1, C2, C3, C4>(C0, C1, C2, C3, C4) -> TupleView<(C0, C1, C2, C3, C4)>
...
复制代码

Our two Textexamples, the compiler automatically (by convention the name) using a static func buildBlock<C0, C1>(C0, C1) -> TupleView<(C0, C1)>method, this time the VStackkind of became VStack<TupleView<(Text,Text)>>a. After ViewBuilderthe conversion code:

struct ContentView : View {
  var body: some View {
    VStack(alignment: .leading) {
      ViewBuilder.buildBlock(Text("Hello, World"), Text("Leon Lu"))
    }
  }
}
复制代码

It is worth mentioning that, due to buildBlockthe overload of generic versions of most parameters is 10. So when more than 10 can be used when Groupthe package it; if there are cycles can be expanded, you can use ForEach.

3. FunctionBuilder case the branch condition

ViewBuilder There are two types of functions is used to construct containing the branch condition when

static func buildEither<TrueContent, FalseContent>(first: TrueContent) ->
 ConditionalContent<TrueContent, FalseContent>

static func buildEither<TrueContent, FalseContent>(second: FalseContent) -> 
 ConditionalContent<TrueContent, FalseContent>

复制代码

If the returned different views based on different criteria, then the type included in the generated two types.

struct SlideViewer: View {
  @State private var isEditing = false
  @Binding var slide: Slide

  var body: some View {
    VStack {
      Text("Slide #\(slide.number)")
      if isEditing {
        TextFiled($slide.title)
      } else {
        Text(slide.title)
      }
    }
  }
}
复制代码

In this case, VStackthe type becomesVStack<TupleView<(Text, ConditionalContent<TextField,Text>)>>

Epilogue

From the naming @_functionBuilderunderlined contained can be seen, Function as well as the possibility of some fine-tuning Builder, and therefore the text to the perspective of pragmatism ViewBuilder to introduce what Function Builder Yes.

SwiftUI and Swift 5.1 New Features series so far temporarily paragraph, if necessary, will continue to update and supplement.

Thank you for the love, in the future there will be more articles to bring you, hope you like it.

related articles:

Swift 5.1 SwiftUI and new features (1) Opaque Opaque Result Type Return Type

SwiftUI and Swift 5.1 New Features (2) the property broker Property Delegates

SwiftUI and Swift 5.1 New Features (3) Key Path Member Lookup

Scanning the next Fanger Wei code, concerned about "the interviewer Kin"

Reproduced in: https: //juejin.im/post/5d0b2fa45188252e2e078170

Guess you like

Origin blog.csdn.net/weixin_33858336/article/details/93182274