SwiftUI - some
some (수식어)
정의 : 해당 키워드가 반환 타입 앞에 붙을 경우, 해당 반환 타입이 불투명한 타입(Opaque Type)이라는 것을 나타낸다.
불투명한 타입 = 역 제네릭 타입(reverse generic types)
제네릭 타입
func swap<T>(a: inout T, b: inout T) { } |
- 타입에 의존하지 않는 범용 코드를 만들 때 사용
- 함수를 작성할 당시엔 실제 어떤 타입이 들어올지에 대해서는 당연히 알 수 없음
- 제네릭 함수의 실제 타입에 대해서는 함수를 호출하는 외부에서 알 수 있음
불투명한 타입(Opaque Type)
struct Apple {}
struct Cherry {}
protocol GiftBox {
associatedtype giftType
var gift: giftType { get }
}
struct AppleGiftBox: GiftBox {
var gift: Apple
}
struct CherryGiftBox: GiftBox {
var gift: Cherry
}
func makeGiftBox() -> GiftBox {
return AppleGiftBox.init(gift: .init())
}
-> 에러 발생 : Protocol 'GiftBox' can only be used as a generic constraint because it has Self or associated type requirements
- 외부에서 함수의 반환 값 유형을 정확하게 알 수 없음
- 다만 함수 내부에서는 어떤 타입을 다루는지 정확히 알고 있음
- GiftBox의 gift 프로퍼티가 associatedtype으로 선언되어 있어서,
- "외부"에선 해당 GiftBox 안에 어떤 타입의 gift가 들어있는지를 알 수 없음
- 실제 타입을 함수 "내부"에서 알 수 없고, "외부"에서 결정 짓는 게 제네릭 타입이었다면,
- 실제 타입을 함수 "외부"에선 알 수 없고, "내부"에서 결정 짓는 게 불투명 타입
- 함수 내부의 내용을 바꿔버리면(AppleGiftBox->CherryGiftBox) 리턴 타입이 바뀐다는 것
- 내 함수는 반환타입이 내 변심에 의해 바뀔 수는 있지만, 항상 특정 타입(사과)만 반환한다고 컴파일러(받는 사람)에게 알릴 때 사용하는 것이 some이라는 키워드이다.
func makeGiftBox() -> some GiftBox {
return AppleGiftBox.init(gift: .init())
}
-> some을 추가하여 반환 타입인 GiftBox가 불투명 타입이 돼서 에러가 사라짐
여기까지의 내용 정리
some이란 것은
명확하지 않은 타입(associatedType or Self)이 프로토콜 내에 정의되어 있고,
이 프로토콜을 함수(및 연산 프로퍼티)의 반환 타입으로 가질 때
반환 타입을 "불투명 타입"으로 만들어주기 위해 사용하고,
some이라는 것을 통해 반환 타입을 "불투명 타입"으로 만든단 것은,
반환 타입이 어떤 타입인지 컴파일러(및 함수 외부)는 모르겠지만
함수 내부에선 어떤 타입을 반환하는지 명확히 알고 있고,
따라서 내 함수는 정해진 "특정 타입만 반환"된다고 컴파일러에게 알려주는 것
some View
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
- body는 View라는 프로토콜에 정의된 프로퍼티
- 이 프로퍼티는 연산 프로퍼티(Comeputed Property)로 Text를 return 하고 있음
- View라는 프로토콜의 속성 중에 associatedtype으로 선언 되어 있다.
위에서 body는 특정 타입(현재는 내가 Text를 리턴 했으니 Text)만 항상 반환된단 것을 알려주는 것이 some(불투명 타입)이다.
some 사용 이유
이렇게 불투명한 타입(some)을 사용할 경우, 함수 내부에서 내가 짜는 코드에 따라 시시각각 리턴 타입이 변경 되었지만(Text->Button) 이거에 대해 따로 본인이 리턴 타입을 바꿔줄 필요가 없다.
만약 some을 통해 불투명 타입으로 선언하지 않으면 body의 타입을 일일이 명명해줘야 한다.
ex) var body: VStack<TupleView<Text,Image>> { … }
불필요한 타입은 컴파일러가 알아서 함
참고 : [https://babbab2.tistory.com]