
우리가 SwiftUI로 UI를 그릴 때마다,
반드시! 마주치는 프로토콜과 변수가 있죠!!
바로
View와 body입니다.
이렇게 어떤 View를 사용자 정의 생성하기 위해서는 body라는 변수가 반드시 필요하죠!!
struct MyView: View {
var body: some View {
...
}
}
여기서 body가 채택한 프로토콜인 View 옆에 some 키워드를 붙여주는 이유는 무엇일까요??
이를 이해하기 위해서는 body라는 변수의 특성과, View 프로토콜과의 관계에 대해서 이해하면 확실하게 이해가 가능합니다.
더불어 some 키워드의 활용법도 완전히 이해하실 수 있을거에요!!
우리가 View를 사용하기 위해서는 MyView 오른쪽에 있는 저 View 프로토콜을 채택해야만 하는데요!
SwiftUI 문서를 보아도, View 프로토콜을 채택하게 되면 다음과 같이 반드시 @ViewBuilder var body가 필요하다는 것을 알 수 있습니다.
associatedtype Body : View <- 요건 타입입니다!
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {
associatedtype Body : View
@ViewBuilder var body: Self.Body { get }
}
그렇다면 이 body 변수는 뭘까요???
Apple 공식문서에는
The type of view representing the body of this view.
When you create a custom view,
Swift infers this type from your implementation of the required body property.
이렇게 설명되어 있습니다.
맨 윗줄은
View의 body를 나타내는 type 이라는 아주 뻔한 말로 설명이 되어있네요.
우리도 다 알고 있듯이, body는 View의 모양을 결정하는 역할을 하죠??
하지만 이 다음 말은 좀 어렵습니다.
우리가 View를 만들 때, Compile 단계에서 View의 body 타입을 "유추"한다.
는 말 인 것 같은데요.
이렇게만 이해하면 알쏭달쏭합니다.
먼저 body의 타입은 정해져 있지 않습니다.
body는 get-only 연산프로퍼티이고, View 프로토콜을 충족하는 어떤 Type도 될 수 있기 때문이에요!!
뭐가 될지는 몰라요! 우리가 어떤 걸 구현하면, 그 타입이 됩니다!!
좀 더 나아가서, body는 View 프로토콜을 충족하는 어떤 타입입니다.
이 말이 이해가 잘 가지 않으신다면, 접은 글로 설명을 달아놓을테니 꼭 읽어보시길 바래요!!
body가 View 프로토콜을 충족하는 어떤 타입이라는 의미는?
방금 보셨던 View Protocol 내부 구조를 다시 한번 들여다봅시다!
@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
public protocol View {
associatedtype Body : View
@ViewBuilder var body: Self.Body { get }
}
아까 넘어갔었던 associatedtype Body : View <- 요 녀석 있죠??
먼저 Associated Type 은 typealias입니다. 즉, Body라는 타입이 있는데, 이 타입은 View 프로토콜을 채택한 타입인거죠!!
그리고 우리가 구현해야 하는 body는 바로 이 Body 타입의 변수입니다.
정리해볼까요??
body는 View 프로토콜을 채택한 Body라는 타입의 변수입니다.
여기서 중요한 것은 결국 우리가 구현해야 하는 body도 View 프로토콜을 채택하고 있다는 것입니다.
body도 View 프로토콜을 채택하고 있다는 이 사실이 왜 중요하느냐?
이게 Compile 단계에서 View의 body 타입을 "유추"한다는 이 문장을 이해할 수 있는 열쇠이기 때문이에요!
우리는 View가 Type이 아닌 Protocol 이라는 것에 집중해야 합니다.
즉, View 프로토콜을 충족하기만 하면, 어떤 타입이든 body 변수의 타입이 될 수 있다는 거에요.
똑같은 말을 계속 반복했네요ㅋㅋㅋ 이제 한걸음 더 나아가 보겠습니다!!
우리가 자주 사용하는 View 프로토콜을 충족한 view들을 볼까요?
// 1
Text("Hello World")
// 2
Text("Hello World")
.padding(.all)
// 3
Text("Hello World")
.foregroundColor(.red)
.padding(.all)
// 4
RoundedRectangle(cornerRadius: 25.0)
// 5
RoundedRectangle(cornerRadius: 25.0)
.stroke(lineWidth: 3)
// 6
RoundedRectangle(cornerRadius: 25.0)
.stroke(lineWidth: 3)
.foregroundColor(.blue)
// 7
ZStack {
Text("Hello World")
}
// 8
ZStack {
Text("Hello World")
RoundedRectangle(cornerRadius: 25.0)
}
대충 8개를 가져왔는데,
이 8개의 type은 모두 다릅니다!
조금 더 자세히 이야기하자면, SwiftUI에는 view modifier라는 것이 있는데, 우리가 위에서 했던 것처럼 padding 등을 추가할 때마다 상황에 맞추어 modified된 view가 되는 것입니다.
1번은 Text 라는 자료형이고,
2번은 Text에 padding이 더해진 어떤 자료형입니다.
모두 View 프로토콜을 충족하는 다른 구조체들인거죠!
그리고 이 View 구조체들은 각각 다른 타입을 가지고 있습니다!
자 우리는 1번이나 4번 정도는 Text, RoundedRextangle 이라고 타입을 명시해줄 수 있지만,
나머지는 어떤 타입인지 명시해줄 수가 없어요.
SwiftUI 코드를 열심히 뜯어봐서 Text<.....> 이런 식으로 만들어줄 수 있겠지만, 배보다 배꼽이 크겠죠??
그래서 사용하는 것이 some 키워드 입니다.
var body: some View {
ZStack(content: {
RoundedRectangle(cornerRadius: 25.0)
.stroke(lineWidth: 3)
.foregroundColor(.blue)
Text("Hello World")
.padding(.all)
})
.padding(5)
.ignoresSafeArea()
}
body와 함께 사용하죠??
some 키워드를 통해 만들어진 타입은 Opaque Types 입니다.
불투명한 타입이라고 해석할 수 있는 이 타입은, compile 단계에서 구체적인 타입이 정해지게 됩니다.
쉽게 이야기하면,
some View는 이 자체로 어떤 타입을 의미하는 것이 아니라,
View 프로토콜을 충족하는 어떤 타입
이라는 뜻입니다!!
자 그러면,
View를 만들 때, Compile 단계에서 View의 body 타입을 "유추"한다.
이 말이 이제 이해가 가실거에요!
마지막으로 정리하자면 다음과 같습니다.
우리가 만들어내는 커스텀뷰 구조체의 body는 View 프로토콜을 충족하는 어떤 타입도 될 수 있기 때문에,
미리 타입을 결정할 수 없고, 컴파일 단계에서 타입을 유추하게 됩니다.
그리고 이를 위해, some 키워드를 사용해서 Opaque Types로 body 연산프로퍼티를 선언합니다.
쓰고 보니 너무 글을 쓸데없이 길게 쓴 것 같기도 하네요
이해가 가셨으면 좋겠습니당...ㅎㅎㅎ
'iOS 개발 > SwiftUI' 카테고리의 다른 글
[SwiftUI] @escaping에 대해서 (2) | 2022.04.11 |
---|---|
[SwiftUI] inout은 어떻게 작동하는가 (C언어의 Call by Reference와 비교) (0) | 2022.03.21 |
[SwiftUI] Generics 타입 제약 (Type Constraints) 다루기 (0) | 2022.03.20 |
[SwiftUI] ForEach에서 \.self를 사용하는 이유와 id 중복 문제 해결 방법 (0) | 2022.03.13 |
[SwiftUI] json parsing 방법 (0) | 2022.03.10 |
[SwiftUI] View 가독성을 늘리는 3가지 방법 (View 쪼개기) (0) | 2022.03.10 |
[Swift UI] @State에 대한 아주 얕은 고찰 (0) | 2021.11.07 |
[SwiftUI] Swift UI에 대한 첫인상 (2) | 2021.11.07 |