이전 게시물 : SwiftUI Views - Basic Concepts (뷰 기본 개념)

 

 

The View

struct BasicSyntax: View {
    var body: some View {
        Text("Hello World!") // 스크린에 text view를 추가합니다.
    }
}

SwiftUI에서 View들은 View Protocol을 따르는 구조체(Structures) 타입입니다. 구현하기 위해서 단 한가지의 Property만 있으면 되는데, 바로 body Property입니다.
참고) 만약 body가 Property라면, get과 return 요소는 어디로 갔을까요?

 

Property Getters

struct Person {
    // Computed read-only property (no set, value is not stored)
    // 읽기 전용 프로퍼티로 설계되었음 (set, value가 저장되지 않음)
    var personType: String {
        get {
            return "human"
	} 
    }
}

Property들은 getter와 setter를 가지고 있을 수 있습니다. 그런데 Property에 setter가 없을때, 그 Property는 read-only property라는 이름을 가집니다. 또한 Property가 value를 저장하지 않을때, computed property라고 부릅니다. Property가 읽힐때마다 값이 계산되거나 생성되기 때문입니다. 위의 예시에서는 personType이 computed read-only property입니다.

 

이 Property는 다음과 같은 두가지 방법으로 더 간단하게 만들 수 있습니다.

// 변경사항1: return 제거
struct Person {
    var personType: String {
	get { 
   	"human"
	}
    }
}

코드의 get 내부에 하나의 expression만 있다면, getter는 자동으로 return을 해줍니다. 따라서 return을 지워도 상관 없습니다.

// 변경사항2: get 제거
    var personType: String {
        "human"
    } 
}

Property가 read-only(setter가 없을 때)인 경우, get을 지울 수 있습니다. 

일단은 이러한 수정방법을 알고 취향껏 하면 됩니다.

 

SwiftUI With Property Getters

이러한 property의 변화는 선택적이기 때문에 이전 SwiftUI문법인 get과 return을 body property에 넣어 작성해도 됩니다. 다음 코드는 아마 당신에게 더 친숙할 것 입니다.

// SwiftUI with the get and return keywords
struct BasicSyntax: View {
    var body: some View {
        get {
            return Text("Hello World!")
        }
    }
}

코드를 다시 한번 들여다보면, some이라는 키워드를 발견할 수 있습니다. 보통, Property의 type을 정의할 때, 이러한 단어를 본적이 없ㅇ르 것입니다.

그렇다면 some 키워드가 하는 것은 어떤 역할일까요?

 

Opaque Types

struct BasicSyntax: View {
    var body: some View {
        Text("Hello World!")
    }
}

some이라는 키워드는 opaque type이 반환되는 것을 지정해줍니다. 위의 경우 opaque type은 View입니다. 그래서 왜 이러한 type을  opaque라고 부를까요? opaque라는 영단어의 정의를 보면, "이해하기에 어렵거나 불가능"하다는 뜻이 있습니다. 그리고 opaque type은 value의 type정보와 implementation detail들을 숨기기 때문에 문맥에 상통하는 부분이 있습니다. 이 타입은 확실히 "이해하기 어렵거나 불가능"하지만, 사용 가능함을 의미합니다.

iOS가 화면을 그리기 위해 BasicSyntax가 사용되는 경우, 이 예에서 텍스트 type이 return되는 것을 알 필요가 없습니다. some View가 return되고 있으며 화면을 그리는 데 사용할 수 있다는 것만 알면 됩니다. 그리고 이 body property에서는 View protocol을 따르는 모든 것이 return될 수 있습니다. Opaque Type들에 대해 더 잘 알아보고 싶다면 Swift Programming Language documentation을 참고하면 됩니다. 

Opaque type에 대한 중요한 정보가 더 남아있는데....

 

Opaque Types (some Keyword)

이미 이전 단계에서 body property에서 무엇을 리턴받는지에 대한 답이 View protocol을 따르는 어떠한 것이라고 알게 되었습니다. 그러나 (some 키워드를 사용하여) opaque type을 리턴할 때도 가능한 모든 유형이 동일한 유형이어야 합니다.

대부분의 경우 한 가지 type만 return 합니다. 하지만 다음과 같은 시나리오가 있을 수 있습니다.

struct UnderstandingTheSomeKeyword: View {
    var isYellow = true
    // some 키워드는 우리에게 무엇을 리턴받던, 다음과 같아야한다고 말해줍니다.
    // 1. View protocol을 따라야한다.
    // 2. Return받는 View의 type은 항상 같아야한다.
    var body: some View {
        // ERROR: 함수는 opaque return type으로 선언했지만, body의 return statements 안에는
        //일치하는 하위 type이 없습니다.
        if isYellow {
            return Color.yellow // Color type은 Text type과 매치되지 않습니다.
}
        return Text("No color yellow") // Text type은 color type과 매치되지 않습니다.
    }
}

body property 는 Color와 Text type을 return합니다. 이것은 some 키워드를 위반합니다.

 

Opaque Types Solution

해결 방법은 return된 view들을 모두 동일한 type으로 변경하는 것입니다. 이제 body는 동일한 type의 view(Color)를 반환합니다.

 struct UnderstandingTheSomeKeywordSolution: View {
 var isYellow = true
 // The keyword "some" tells us that whatever we return, it has to:
 // 1. Conform to the View protocol
 // 2. Has to ALWAYS be the same type of View that is returned.
var body: some View {
        return Color.clear
    }
}
이제 body property는 항상 색상 유형을 return합니다. 이것은 some 키워드를 만족시킨다.
 
 

View Containers 

struct Example: View {
    var body: some View {
        VStack {
            Text("Hello World!")
            Text("This Vertical Stack is using a function builder")
        } 
    }
}

지금까지 body는 computed read-only property이며 some View인 하나의 object만 반환할 수 있다는 것을 배웠습니다. 만약 여러 보기를 표시하고 싶다면 어떻게 해야 할까요?

앞에서 "containers" view의 개념에 대해 배웠습니다. 다른 view를 포함할 수 있는 view입니다. body property는 하나의 view만 return할 수 있습니다. body property에서 둘 이상의 view를 return하려고 하면 오류가 발생합니다.

위의 예에서 VStack(Vertical Stack)은 return되는 하나의 view입니다. 그리고 그 VStack은 내부에 두 개의 view가 더 있는 container입니다.

VStack은 "trailing closure"를 사용하는데, 이는 VStack이 실행시킬 initializer로 전달되는 코드 블록이라는 의미입니다. Swift에서 한번쯤 봤을법한 것입니다.

Swift에서 새로운 것은 constructor 내에서 여러 개의 새로운 view를 생성할 수 있는 기능입니다. 이 문제를 시작하기 전에 이 constructor의 작동 방식을 더 잘 이해하도록 합시다.

 

View Container Initialization

Swift에서는 일반적으로 초기화 중에 괄호를 사용하지만, trailing closure 되는 경우에는 괄호가 선택 사항입니다.
그것들을 추가해도 코드는 여전히 정상적으로 작동합니다.

코드 예제에서 "Change 1"을 참조하십시오.

이러한 변화는 여러분에게 더 친숙해 보이기 시작할지도 모릅니다. 자, 질문은 이것입니다.

VStack은 어떻게 이와 같은 여러개의 View들을 수용하는 방법을 알고 있습니까?

이 내용은 Swift에서 새로운 것입니다. 이를 더 잘 이해하려면 VStack의 initializer를공부해야합니다.

alignment와 spacing 파라미터는 선택 사항이기 때문에 위의 예제에서 볼 수 없습니다. 대신 content 파라미터 앞에 @ViewBuilder 구문이 있음을 유의하세요.

그것이 content 파라미터의 closure내에서 여러 개의 뷰들을 선언할 수 있도록 해주는 것입니다. 

struct Example: View {
       var body: some View {
           VStack {
               Text("Hello World!")
               Text("This Vertical Stack is using a function builder")
           } 
       }
   }
}
   // Change 1 - Add parentheses and parameter name
   struct Example: View {
       var body: some View {
           VStack(content: {
               Text("Hello World!")
               Text("This Vertical Stack is using a function builder")
           })
       }
    } 
}
   // VStack initializer
   init(alignment: HorizontalAlignment = .center, spacing: CGFloat? = nil,
   @ViewBuilder content: () -> Content)

 

@ViewBuilder Parameter Attribute

@ViewBuilder 파라미터 속성을 통해 Swift는 closure 내에서 여러 child view들을 빌드할 수 있습니다.

Closure 내에서 몇 개의 child view를 빌드할 수 있을까요?

관련 기능은 이미 개수가 정해져 있습니다. 우리는 최대 10개의 view만 initialize할 수 있습니다. 여기 예제에서는 11번째 뷰 때문에 오류가 발생합니다.

Child view가 더 필요하면 어떻게 합니까?

사용자 인터페이스에 대해 더 많은 child view를 선언해야 하는 경우 다른 view container(다른 VStack 등)을 사용해야 합니다.

두 번째 예제에서는 텍스트 뷰 10과 텍스트 뷰 11을 포함하기 위해 다른 VStack을 사용합니다.

struct ViewBuilderExample: View {
    var body: some View {
        VStack {
            Text("View 1")
            Text("View 2")
            Text("View 3")
            Text("View 4")
            Text("View 5")
            Text("View 6")
            Text("View 7")
            Text("View 8")
            Text("View 9")
            Text("View 10")
            Text("View 11") // Will cause an error
        }
    }
}
struct ViewBuilderExample: View {
    var body: some View {
        VStack {
            ... // Text views 1 - 5
            Text("View 6")
            Text("View 7")
            Text("View 8")
            Text("View 9")
            VStack { // The VStack is now the 10th view
                Text("View 10")
                Text("View 11")
            }
        }
    }    
}

 

 

이 포스트는 밑의 페이지의 자료를 읽고 나서, 의역이 다소 존재하는 번역글입니다.

 

'IOS' 카테고리의 다른 글

CoreData 기술 공유  (1) 2022.07.05
SwiftUI Views - Basic Concepts  (0) 2022.04.29
SwiftUI Search Bar / 검색 기능 구현하기  (0) 2022.04.28
SwiftUI에서 리스트 동적으로 사용하기 (1)  (0) 2022.04.28
iOS 개인 프로젝트 시작  (0) 2022.04.28

+ Recent posts