스위프트를 가능하게 하는 것UI의 DSL?
애플이 새로 나온 것 같습니다.SwiftUI
framework는 튜플을 효과적으로 구축하는 새로운 종류의 구문을 사용하지만 다른 구문을 사용합니다.
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
가 되는 것SwiftUI
type이 이 가정을 뒷받침합니다.아니면 스위프트 구문이 유효한가요?만약 그렇다면 밖에서 어떻게 사용할 수 있습니까?
마틴이 말했듯이, 의 문서를 보면,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
기구들buildBlock
1인에서 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 비디오에 설명되어 있습니다.속성은 컴파일러에 의해 해석되고 관련 코드로 변환됩니다.
언급URL : https://stackoverflow.com/questions/56434549/what-enables-swiftuis-dsl
'programing' 카테고리의 다른 글
if 조건의 쉼표 연산자 (0) | 2023.11.04 |
---|---|
워드프레스 도커 컨테이너로 리디렉션할 nginx 하위 경로 (0) | 2023.11.04 |
"ui-sref"는 링크를 두 번 클릭해도 "ui-view"(컨트롤러가 다시 실행되지 않음)를 새로 고치지 않습니다. (0) | 2023.11.04 |
스프링 부트 탄성 검색 구성 (0) | 2023.11.04 |
connect to maria db with mauricio/postgresql-mysql driver in play2.5 (0) | 2023.11.04 |