
SwiftUIλ‘ μ±μ λ§λ€λ€ 보면,
bodyμμ λ·°λ₯Ό λ°νν λ μ’ μ’some ViewλΌλ ννμ λ³΄κ² λ©λλ€.someμ λλ체 λκΉμ?
그리κ³any,AnyView,@ViewBuilderλ μΈμ μ¨μΌ ν κΉμ? μ΄μ λν΄ νν€μ³λ³΄μμ΅λλ€!
Opaque Type: λΆν¬λͺ νμ
νκ΅λ§λ‘λ λΆν¬λͺ
νμ
μ΄λΌκ³ νλλ°μ, SwiftUIμμ some ν€μλλ₯Ό λΆμΈ νμ
μ Opaque Typeμ΄λΌκ³ ν©λλ€!
struct BasicView: View {
var body: some View {
Text("Hello, World!")
.bold()
.background(.yellow)
.foregroundStyle(.red)
.padding()
.background(.blue)
.jack()
}
}
body νλ‘νΌν°μ νμ
μ΄ some View λ‘ λμ΄μλ κ±Έ λ³Ό μ μμ΅λλ€.μ μ½λλ₯Ό 보μλ©΄ Textμ μ¬λ¬ View Modifierκ° μ²΄μ΄λ λμ΄μλ κ±Έ λ³Ό μ μλλ° μ΄μ°¨νΌ body μ°μ° ꡬ문 λ΄μ Textλ°μ μλ κ±° some View λμ Text λ₯Ό μ°λ©΄ μλλ κ±ΈκΉμ? μ κ΅³μ΄ some ν€μλλ₯Ό λΆμ¬μ Opaque Typeμ΄λΌλ κ²μ μ¬μ©νλ κ±ΈκΉμ?
print(Mirror(reflecting: self).subjectType)
ModifiedContent<ModifiedContent<ModifiedContent<ModifiedContent<Text, _BackgroundStyleModifier<Color>>, _ForegroundStyleModifier<Color>>, _PaddingLayout>, _BackgroundStyleModifier<Color>>
κ²°κ³Όλ μ΄λ κ² λμ΅λλ€.. View Modifierμ λΆμ΄λ©΄ λΆμ΄λ λλ‘ μ£λ€ νμ λͺ μ΄ λκ³ μ λ€λ¦μ μ λ€λ¦μ μ λ€λ¦μ΄ λμ΄.. μμ£Ό κΈΈκ³ λ³΅μ‘νκ² λμ΅λλ€..!
μ΄κ±Έ νμ
λͺ
μΌλ‘ μΈ μλ μμ§λ§ κ·Έλ κ² νκΈ°μ λ무 볡μ‘νκΈ° λλ¬Έμ μ΄λ° 볡μ‘ν νμ
λͺ
μ μ¨κΈ°κ³ μ μ¬μ©νλ κ²μ΄ some View (Opaque Type) μ
λλ€!
Opaque Typeμ νμ μ μ¨κΈ΄λ€κ³ νλλ° κ·Έκ±΄ κ°λ°μ λμλ§ μ¨κΈ°κ³ , μ»΄νμΌλ¬μκ²λ μμ£Ό ν¬λͺ νκ² μ 보μ λλ€.
κ·Έλμ μ»΄νμΌ μμ μ νμ μ΄ νμ λμ΄ μ΄λ μ μ λμ€ν¨μΉ(static dispatch)λ‘ λμν μ μκ² νκΈ° λλ¬Έμ μ΅μ νκ° κ°λ₯ν΄μ§λλ€!
private func textButton() -> some View {
VStack {
Image(systemName: "star")
Text("λ²νΌ")
}
}
ꡬνλΆμμ some View λ₯Ό λ°ννμ§λ§ μ΄κ±΄ ꡬ체 νμ
μ λ°ννκΈ° λλ¬Έμ μ»΄νμΌλ¬κ° κ·Έ νμ
μ μ νν μ μ μμ΅λλ€.
μ λ€λ¦κ³Ό λ¬λ¦¬ ꡬνλΆμ ꡬ체μ νμ μ΄ λ€μ΄κ°κ³ νΈμΆλΆλ₯Ό μΆμνμν€κΈ° λλ¬Έμ μμ λ€λ¦μ΄λΌκ³ λ λΆλ¦ λλ€.
some)κ³Ό Existential Type (any)μ μ°¨μ΄μ Swiftμμλ
someκ³Όanyλ λ€ νλ‘ν μ½ νμ μ ννν λ μ¬μ©λμ§λ§, μν κ³Ό λμ λ°©μμ΄ μμ ν λ€λ¦ λλ€.
func getRandomView() -> any View {
if Bool.random() {
return Text("Hello")
} else {
return Button("Click me") {}
}
}
any Viewλ Swift 5.7λΆν° λμ
λ μ‘΄μ¬ νμ
(existential type)μ λͺ
μμ μΌλ‘ νννλ λ°©μμ
λλ€. μ΄μ μλ κ·Έλ₯ ViewλΌκ³ λ¨μν νλ‘ν μ½ ννλ‘ μΌλ€λ©΄, μ΄μ λ any Viewλ‘ ννν©λλ€.
μ΄λ κ² νλ©΄ μ»΄νμΌλ¬κ° ν΄λΉ νμ μ΄ λμ λμ€ν¨μΉλ₯Ό μ¬μ©νλ μ‘΄μ¬ νμ μ΄λΌλ κ²μ λͺ ννκ² μΈμν μ μκ² λ©λλ€!
"ν΄λΉ νλ‘ν μ½μ μ€μνλ νμ μ΄Β μ‘΄μ¬νλ€"λΌλΒ μλ―Έ
Swiftμμ νλ‘ν μ½μ νμ μΌλ‘ μ¬μ©ν λ μκΈ°λ κ°λ μΌλ‘, λ°ν κ°μ΄Β νΉμ νλ‘ν μ½μ μ€μνλ€λ μ¬μ€λ§ 보μ₯νκ³ Β κ΅¬μ²΄μ μΈ νμ μ μ¨κΈ°λΒ λ°©μμ λλ€.
μ€μ μ¬μ©λλ ꡬ체 νμ μ λν΄μλΒ λ°νμμ μ μ μμ΄μ μ±λ₯μ μΌλ‘ λΆλ¦¬ν μ μ΄ μμ μ μμ΅λλ€.
some - Opaque Typeany - Existential TypeμκΉ ν΄λΉ νμ μ΄ λμ λμ€ν¨μΉλ₯Ό μ¬μ©νλ μ‘΄μ¬ νμ μ΄λΌλ κ²μ λͺ ννκ² μΈμν μ μκΈ° λλ¬Έμ΄λΌκ³ νλλ°μ, μ’ λ μμΈν μ΄ν΄λ³΄μλ©΄
var view: View // Swift 5.6 μ΄μ
var view: any View
μ μ½λμμ viewλ λ΄λΆμ μΌλ‘ existential containerλ‘ μ²λ¦¬λμμ΅λλ€. μ¦, λ€μν View νμ
μ λ΄μ μ μλ μΌμ’
μ λνΌ νμ
μΈλ°, μ»΄νμΌ νμμλ ꡬ체 νμ
μ μ μ μμ΅λλ€.
μ΄λ¬ν existential νμ μ¬μ©μ΄ λ°νμ λΉμ©μ μ λ°ν μ μλ€λ μ , κ·Έλ¦¬κ³ μΌλ°μ μΈ μ λ€λ¦ νμ κ³Ό ꡬλΆλμ§ μλλ€λ μ μ΄ νΌλμ μΌμΌμΌ°μ΅λλ€.
κ·Έλμ any λ₯Ό λΆμμΌλ‘μ¨ κ΅¬μ²΄ νμ
μ΄ μλ νλ‘ν μ½μ νμ
μΌλ‘ μ΄λ€λ μλ―Έλ₯Ό λͺ
νν μ λ¬ν μ μμ΅λλ€.
// Generic: ꡬ체 νμ
μ μ»΄νμΌ νμμ κ²°μ λ¨
func render<V: View>(_ view: V) { ... }
// Existential: μ΄λ€ Viewλ λ΄μ μ μμ (μ»΄νμΌλ¬λ λ΄λΆ νμ
μ λͺ¨λ¦)
func render(_ view: any View) { ... }
κ³Όκ±°μλ Viewλ§ μ¨λ existentialμ΄μκΈ° λλ¬Έμ μ΄ λμ΄ λΉμ·ν΄ 보μμ§λ§, μ€μ λ‘λ νΌν¬λ¨Όμ€μ νμ
μμ€ν
μμ λ€λ₯΄κ² μλνμ΅λλ€.
any ν€μλλ μ΄ μ°¨μ΄λ₯Ό λͺ
νν 보μ¬μ£Όλ μν μ ν©λλ€.
associatedtypeμ΄λ Selfλ₯Ό ν¬ν¨νλ νλ‘ν μ½μ μ¬μ ν anyλ₯Ό λΆμ¬λ μ‘΄μ¬ νμ
μΌλ‘ μ¬μ©ν μ μμ΅λλ€.
μ΄λ° νλ‘ν μ½μ λ΄λΆμ μΌλ‘ ꡬ체μ μΈ νμ μ΄ κ²°μ λμ΄μΌ νκΈ° λλ¬Έμ, μ»΄νμΌλ¬κ° ν΄λΉ νμ μ μΆλ‘ ν μ μλ μν©μμλ νμ μΌλ‘ μ¬μ©ν μ μλ κ²μ΄μ£ .
μλ₯Ό λ€μ΄ λ€μκ³Ό κ°μ νλ‘ν μ½μ anyλ₯Ό λΆμ¬λ μλ¬κ° λ°μν©λλ€:
protocol IdentifiableItem {
associatedtype ID
var id: ID { get }
}
let item: any IdentifiableItem // μ»΄νμΌ μλ¬
Swift 5.7 μ΄μ μλ μ΄λ° μ μ½μΌλ‘ μΈν΄ ν·κ°λ¦¬κ±°λ, λͺ ννμ§ μμ μλ¬ λ©μμ§κ° μΆλ ₯λλ κ²½μ°λ μμμ΅λλ€.
νμ§λ§ any λμ
μ΄νμλ βμ΄ νλ‘ν μ½μ μ‘΄μ¬ νμ
μΌλ‘ μ¬μ©ν μ μλ€"λ κ±Έ μ»΄νμΌ νμμ νμ€νκ² μλ €μ€λλ€.
λλΆμ κ°λ°μλ μ΄λ€ νλ‘ν μ½μ΄ μ λ€λ¦μΌλ‘λ§ μ¬μ© κ°λ₯νμ§, μ΄λ€ νλ‘ν μ½μ΄ μ‘΄μ¬ νμ μΌλ‘ μΈ μ μλμ§λ₯Ό ν¨μ¬ μ§κ΄μ μΌλ‘ ꡬλΆν μ μμ΅λλ€.
any Viewλ Swift 5.7 μ΄ν λ±μ₯ν μλ‘μ΄ νμ
μ μΈ λ°©μμ΄λΌλ©΄,
AnyViewλ SwiftUIκ° μ 곡νλ νμ
μ§μ°κΈ°(type-erasing) ꡬ쑰체μ
λλ€.
// Swift 5.6 μ΄μ λ°©μ (νμ
μ§μ°κΈ°)
var body: some View {
AnyView(condition ? Text("A") : Image(systemName: "star"))
}
// Swift 5.7 μ΄ν λ°©μ
func someFunc() -> any View {
// ...
}
AnyViewλ νμ
μ 체μ±μ μ§μ°λ©°, λ€μν ꡬ체μ νμ
λ€μ λ¨μΌ νμ
μΌλ‘ λνν©λλ€. AnyView μμ λ°νμμ λμνμ¬ μ±λ₯μ΄ λ¨μ΄μ§ μ μμ΅λλ€.
any Viewλ AnyViewλ λμ Viewλ₯Ό μ²λ¦¬ν λ μ μ©νμ§λ§, μ±λ₯ λΉμ©μ΄ ν½λλ€. λμ @ViewBuilder λ₯Ό μ¬μ©νλ©΄ νμ
μμ μ±κ³Ό μ±λ₯μ μ μ§ν μ μμ΅λλ€.
@ViewBuilder
func conditionalView(_ condition: Bool) -> some View {
if condition {
Text("A")
} else {
Image(systemName: "star")
}
}
@ViewBuilderλ μ»΄νμΌλ¬κ° View κ³μΈ΅μ λ¨μΌ some Viewλ‘ ν΅ν©νλ©°, μ μ λμ€ν¨μΉλ₯Ό 보μ₯ν©λλ€.
struct ColorHStack<Content>: View where Content: View {
let content: () -> Content
let color: Color
init(color: Color = .clear,
@ViewBuilder content: @escaping () -> Content) {
self.color = color
self.content = content
}
var body: some View {
HStack {
content()
}
.background(color)
}
}
struct ContentView: View {
var body: some View {
ColorHStack(color: .purple) {
Text("Zedd")
Text("Zedd")
}
}
}
μ΄λ°μμΌλ‘λ νμ©ν μ μμ΅λλ€.
μ§κΈκΉμ§ SwiftUIμ Opaque Type λΆν° some, any, AnyView, @ViewBuilderκΉμ§ μμ보μλλ°μ,
μ 리νμλ©΄ SwiftUIμ Opaque Typeμ Swiftμ μ μ νμ μμ€ν κ³Ό μ»΄νμΌλ¬ μ΅μ νμ ν΅μ¬μ λλ€.
some Viewλ μ»΄νμΌ νμμ νμ μ μΆλ‘ νμ¬ μ±λ₯κ³Ό μμ μ±μ ν보νκ³ κ°λ°μλ μ μΈμ UIλ₯Ό κ°κ²°ν μμ±ν μ μκ² ν©λλ€!
μμΌλ‘λ any ν€μλλ‘ μ‘΄μ¬ νμ μμ λͺ μνκ³ any, AnyViewλ³΄λ¨ @ViewBuilderλ‘ μ΅μ ν νλ κ²μ μΆμ²λ립λλ€.
μ½μ΄μ£Όμ μ κ°μ¬ν©λλ€!