programing

스위프트를 가능하게 하는 것UI의 DSL?

minimums 2023. 11. 4. 10:32
반응형

스위프트를 가능하게 하는 것UI의 DSL?

애플이 새로 나온 것 같습니다.SwiftUIframework는 튜플을 효과적으로 구축하는 새로운 종류의 구문을 사용하지만 다른 구문을 사용합니다.

var body: some View {
    VStack(alignment: .leading) {
        Text("Hello, World") // No comma, no separator ?!
        Text("Hello World!")
    }
}

구문이 실제로 무엇인지 다루기 위해 노력하면서, 저는VStack여기에 사용된 이니셜라이저는 유형의 종결을 수행합니다.() -> Content두 번째 매개 변수로서, 여기서Content는 다음을 따르는 일반적인 매개 변수입니다.View폐쇄를 통해 추론할 수 있습니다어떤 유형인지 알아보려면Content코드를 약간 변경하여 기능을 유지한 것으로 유추됩니다.

var body: some View {
    let test = VStack(alignment: .leading) {
        Text("Hello, World")
        Text("Hello World!")
    }

    return test
}

이와 함께.test자신이 활자임을 드러내다VStack<TupleView<(Text, Text)>>, 라는 뜻으로Content유형의TupleView<Text, Text>. 올려다보기TupleView, 원래 포장지 타입인 것을 발견했습니다.SwiftUI랩을 해야하는 튜플을 통과해야만 초기화할 수 있는 그 자체.

질문.

이제 나는 이 둘이 도대체 어떻게 된 것인지 궁금합니다.Text이 예제의 인스턴스는 a로 변환됩니다.TupleView<(Text, Text)>. 이게 해킹당한 건가요?SwiftUI따라서 일반 스위프트 구문이 유효하지 않습니까? TupleView가 되는 것SwiftUItype이 이 가정을 뒷받침합니다.아니면 스위프트 구문이 유효한가요?만약 그렇다면 밖에서 어떻게 사용할 수 있습니까?

마틴이 말했듯이, 의 문서를 보면,content:매개 변수가 속성을 갖습니다.@ViewBuilder:

init(alignment: HorizontalAlignment = .center, spacing: Length? = nil,
     @ViewBuilder content: () -> Content)

이 속성은 생성된 인터페이스를 살펴보면 다음과 같은 유형을 나타냅니다.

@_functionBuilder public struct ViewBuilder {

    /// Builds an empty view from an block containing no statements, `{ }`.
    public static func buildBlock() -> EmptyView

    /// Passes a single view written as a child view (e..g, `{ Text("Hello") }`)
    /// through unmodified.
    public static func buildBlock(_ content: Content) -> Content 
      where Content : View
}

@_functionBuilder속성은 "기능 빌더(function builders)"라고 불리는 비공식적인 기능의 일부이며, 여기에 스위프트 에볼루션(Swift evolution)으로 피칭되어 있으며, 특별히 Xcode 11과 함께 발송되는 스위프트 버전을 위해 구현되어 스위프트에서 사용할 수 있습니다.UI.

유형 표시@_functionBuilder함수, 계산된 속성, 이 경우 함수 유형의 매개 변수 등 다양한 선언에서 사용자 지정 속성으로 사용할 수 있습니다.이러한 주석이 달린 선언은 함수 빌더를 사용하여 코드 블록을 변환합니다.

  • 주석이 달린 함수의 경우 변환되는 코드 블록이 구현됩니다.
  • 주석이 달린 계산 속성의 경우 변환되는 코드 블록이 게터입니다.
  • 함수 유형의 주석이 달린 매개 변수의 경우 변환되는 코드 블록은 해당 매개 변수(있는 경우)로 전달되는 모든 종결 표현식입니다.

함수 빌더가 코드를 변환하는 방법은 다음과 같은 빌더 방법의 구현에 의해 정의됩니다.buildBlock, 식들의 집합을 취하여 하나의 값으로 통합합니다.

예를들면,ViewBuilder기구들buildBlock1인에서 10인까지View매개변수 준수, 여러 보기를 단일로 통합TupleView:

@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension ViewBuilder {

    /// Passes a single view written as a child view (e..g, `{ Text("Hello") }`)
    /// through unmodified.
    public static func buildBlock<Content>(_ content: Content)
       -> Content where Content : View

    public static func buildBlock<C0, C1>(_ c0: C0, _ c1: C1) 
      -> TupleView<(C0, C1)> where C0 : View, C1 : View

    public static func buildBlock<C0, C1, C2>(_ c0: C0, _ c1: C1, _ c2: C2)
      -> TupleView<(C0, C1, C2)> where C0 : View, C1 : View, C2 : View

    // ...
}

이를 통해 다음으로 전달되는 닫힘 내의 뷰 표현식 집합을 허용합니다.VStack전화를 거는 것으로 변화할 최초의 도구.buildBlock같은 수의 인수가 필요합니다.예를 들어,

struct ContentView : View {
  var body: some View {
    VStack(alignment: .leading) {
      Text("Hello, World")
      Text("Hello World!")
    }
  }
}

에 대한 호출로 변환됩니다.buildBlock(_:_:):

struct ContentView : View {
  var body: some View {
    VStack(alignment: .leading) {
      ViewBuilder.buildBlock(Text("Hello, World"), Text("Hello World!"))
    }
  }
}

결과가 불투명한 결과 유형으로 나타납니다. some View로 만족하기TupleView<(Text, Text)>.

당신은 그것을 주목할 것입니다.ViewBuilder정의만 합니다.buildBlock최대 10개의 파라미터를 사용할 수 있으므로 11개의 하위 뷰를 정의하려고 하면 다음과 같습니다.

  var body: some View {
    // error: Static member 'leading' cannot be used on instance of
    // type 'HorizontalAlignment'
    VStack(alignment: .leading) {
      Text("Hello, World")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
      Text("Hello World!")
    }
  }

이 코드 블록을 처리할 수 있는 빌드 방법이 없기 때문에 컴파일러 오류가 발생합니다(이 기능은 여전히 워크인 progress이기 때문에 이를 둘러싼 오류 메시지는 그다지 도움이 되지 않습니다.

실제로, 저는 사람들이 이러한 제약에 자주 부딪칠 것이라고 생각하지 않습니다. 예를 들어, 위의 예는 대신 뷰를 사용하여 더 나은 서비스를 제공할 것입니다.

  var body: some View {
    VStack(alignment: .leading) {
      ForEach(0 ..< 20) { i in
        Text("Hello world \(i)")
      }
    }
  }

그러나 정적으로 정의된 보기가 10개 이상 필요한 경우 보기를 사용하여 이 제한을 쉽게 해결할 수 있습니다.

  var body: some View {
    VStack(alignment: .leading) {
      Group {
        Text("Hello world")
        // ...
        // up to 10 views
      }
      Group {
        Text("Hello world")
        // ...
        // up to 10 more views
      }
      // ...
    }

ViewBuilder는 또한 다음과 같은 다른 함수 작성기 메소드를 구현합니다.

extension ViewBuilder {
    /// Provides support for "if" statements in multi-statement closures, producing
    /// ConditionalContent for the "then" branch.
    public static func buildEither<TrueContent, FalseContent>(first: TrueContent)
      -> ConditionalContent<TrueContent, FalseContent>
           where TrueContent : View, FalseContent : View

    /// Provides support for "if-else" statements in multi-statement closures, 
    /// producing ConditionalContent for the "else" branch.
    public static func buildEither<TrueContent, FalseContent>(second: FalseContent)
      -> ConditionalContent<TrueContent, FalseContent>
           where TrueContent : View, FalseContent : View
}

이를 통해 다음 문장을 처리할 수 있습니다.

  var body: some View {
    VStack(alignment: .leading) {
      if .random() {
        Text("Hello World!")
      } else {
        Text("Goodbye World!")
      }
      Text("Something else")
    }
  }

다음과 같이 바뀝니다.

  var body: some View {
    VStack(alignment: .leading) {
      ViewBuilder.buildBlock(
        .random() ? ViewBuilder.buildEither(first: Text("Hello World!"))
                  : ViewBuilder.buildEither(second: Text("Goodbye World!")),
        Text("Something else")
      )
    }
  }

중복된 1argument 통화를 내보냅니다.ViewBuilder.buildBlock명확하게 하기 위하여).

유사한 내용은 DSL에 관한 섹션(~31:15부터 시작)의 What's New in Swift WWDC 비디오에 설명되어 있습니다.속성은 컴파일러에 의해 해석되고 관련 코드로 변환됩니다.

enter image description here

언급URL : https://stackoverflow.com/questions/56434549/what-enables-swiftuis-dsl

반응형