some이란?
some은 Opaque Type과 관련이 있다.
some을 이해하려면, Opaque타입이 뭔지부터 알아야 한다.
Opaque를 알아보기전에
Opaque타입은 종종 reverse generic 타입이라고 불린다.
그렇기 때문에 Generic타입에 대해서 먼저 알아야 한다.
Generic에 대해서는 Swift의 Generic 빠르게 훑기를 참고하고, 바로 Generic 코드를 보자.
func max<T: Comparable>(_ x: T, _ y: T) -> T {
return (x > y) ? x : y
}
Generic타입은 위처럼 여러 타입을 쓰고자 할 때 사용할 수 있다.
Generic타입에 Comparable제약을 두면서, 우리는 T가 뭔지는 모르지만, 비교가 가능하다는 것은 알기 때문에 우리는 함수의 기능을 구현할 수 있다.
이렇게 Generic타입은 함수를 구현하는 내부에는 값을 숨긴다. (우리가 모르기 때문에 숨긴다는 표현을 사용)
반면 함수 외부에서, 즉 우리가 이 함수를 쓸때는 언제나 어떤 타입이 들어가는지 알 수 있다. (반대로 값이 오픈되어 있다.)
let x = 4
let y = 3
let maximum = max(x, y) // 이 시점에서 우리는 이미 maximum이 Int 타입임을 알고 있다.
그래서 Opaque타입이 뭐야?
앞서 Opaque타입은 reverse generic 타입이라고 했다.
무슨 뜻이냐면, Opaque타입은 Generic타입과 반대로 함수 내부에서는 반환값을 정확히 알 수 있지만, 밖에서는 반환값의 유형을 정확히 알지 못하게 숨기는 것이라 할 수 있다.
현실의 예로 조금 더 쉽게 설명하자면, 장난감이 들어있는 킨더 초콜릿을 떠올려보자.
킨더 초콜릿을 외부에서 보면 전부 똑같이 생겼다.
그러나 내부에는 모두 다른 장난감이 들어있고 이는 내부에서만 알 수 있고 외부에서 알 수 없는 것이다.
이게 바로 Opaque Type이라 할 수 있는 것이다.
코드로 알아보자.
func randomReturn() -> some Collection {
return [1, 2, 3]
}
위와 같은 함수가 있다고 가정하면, 우리는 함수 내부를 구현할 때에는 리턴 값에 대해서 알 수 있다.
반면 외부에서는 어떤 값이 리턴될지 알 수 없다.
Generic타입으로 구현한 함수와 정확히 반대다.
그래서 Opaque타입이 reverse generic 타입이라고 불린다.
그래, 잘 알겠는데 그래서 SwiftUI에는 왜 some이 붙는건데?
SwiftUI 에서의 some
우선 some은 필수 사항이 아니다.
struct ContentView: View {
var body: Text {
Text("Text")
}
}
위처럼 some View 대신 Text라는 Concrete타입을 지정하면 더이상 some 키워드는 사용하지 않아도 된다.
하지만 이런 경우 복잡한 화면을 구성하게 되면 점차 더러워지는 코드를 볼 수 있다.
var body: VStack<TupleView<(Text, Image)>> { ... }
...
var body: VStack<TupleView<(Text, Text, Image)>> { ... }
...
var body: List<Never, TupleView<(HStack<TupleView<(VStack<TupleView<(Text, Text)>>, Text)>>, HStack<TupleView<(VStack<TupleView<(Text, Text)>>, Text)>>)>> { ... }
🤯
이건 정말 말도 안되는 코드라는 것은 설명할 필요도 없다.
이 더럽고 더러운 코드를 some한방에 해결할 수 있는 것이다.
var body: some View { ... }
이게 바로 SwiftUI에서 some키워드를 사용하는 이유이며, 우리도 some 키워드를 사용해야 하는 이유이다.