SwiftUI를 위한 Swift 5.1 기능

Opaque 리턴 타입

  • SwiftUI에서 some이라는 키워드가 눈에 띄었다.
  • some은 opaque 리턴 타입을 선언할 수 있게 해준다.
  • 즉, some을 통해 generic한 protocol도 리턴 타입으로 사용될 수 있다.
  • 가장 대표적으로, some은 SwiftUI의 body에서 사용된다.
struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
    }
}
  • some이 없었다면, 아래와 같이 특정 View 타입을 지정해주거나
struct ContentView: View {
    var body: Text {
        Text("Hello, world!")
    }
}
  • AnyView를 사용해 타입을 지워야한다.
  • 그러면 리턴할때마다 타입을 다음과 같이 지워야한다.
struct ContentView: View {
    var body: AnyView {
        AnyView(Text("Hello, world!"))
    }
}

return 생략

  • 단일 표현 함수는 return 키워드를 생략할 수 있다.
  • 아래의 두 코드는 동일하게 작동한다.
struct ContentView: View {
    var body: some View {
        return Text("Hello, world!")
    }
}

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
    }
}

Function builders

23년 10월 기준 Function Builder는 ResultBuilder로 대체 됨.

  • some 키워드나 return 키워드 생략은 View에 대해 이해가 가능하게 해준다.
  • 하지만 여전히 VStack, HStack, Group에 대한 이해는 불가능하다.
  • 아래와 같은 코드가 return이나 추가 문법 없이 어떻게 하나로 묶이는지 설명이 안된다.
struct HeaderView: View {
    let image: UIImage
    let title: String

    var body: some View {
        VStack {
            Image(uiImage: image)
            Text(title)
        }
    }
}
  • function builder(현재는 @resultBuilder)가 이를 설명해준다.
  • 이에 대한 자세한 설명은, 애플 공식 문서를 참고하자.

Property wrappers

  • property wrapper는 말그대로 property 값이 자동으로 wrap되는 기능이다.
  • SwiftUI에서는 이를 통해, bindable property들을 쉽게 정의할수 있게 도와준다.
  • @State가 하나의 예시가 될 수 있다.
struct Setting: View {
    @State var save: Bool
    @State var enable: Bool

    var body: some View {
        return VStack {
            Toggle(isOn: $save) {
                Text("Save")
            }
            Toggle(isOn: $enable) {
                Text("Enable")
            }
        }
    }
}
  • 위 예시와 같이 @State는 property의 값을 State 타입으로 wrap 해준다.
  • 여기서 property wrapper이 없었다면 아래와 같이 작성해야 할 것이다.
struct Setting: View {
    var save: State<Bool>
    var enable: State<Bool>

    var body: some View {
        return VStack {
            Toggle(isOn: save.binding) {
                Text("Save")
            }
            Toggle(isOn: enable.binding) {
                Text("Enable")
            }
        }
    }
}
  • SwiftUI의 State 구조체는 다음과 같이 단순화 시킬 수 있기 때문이다.
@propertyWrapper
struct State<Value> {
    init(initialValue: Value) {
        ...
    }

    var wrappedValue: Value {
        get { ... }
        set { ... }
    }
}