Type Erasure에 대해 살펴보도록 하겠습니다.
이걸 공부하는 이유는 제가 swiftUI를 공부하면서 뷰 만들 때 항상 some 키워드가 앞에 붙자나요.
맨날 무의식적으로 사용하다가 어느순간 이게 근데 뭐하는건데 왜 붙지 생각이 들어서
관련 내용을 정리해보도록 하겠습니다!
아래와 같이 ContentView를 그리는 View가 있을 때 View 타입 앞에 some 키워드가 붙습니다.
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
some은 computed property또는 함수의 구체적 return Type을 숨기는 것(불투명한 타입)을 제공할 수 있음
(return Type이 불투명한 타입이 이라는 것을 나타냄)
- 불투명한 타입(opaque type)을 제공하는 하는 이유가 뭘까?
불투명한 타입을 통해 의존관계가 발생하지 않는, 유연한 프로그래밍이 가능하게 하는 장점이 있습니다.
그래서.. opaque type은 뭔데요 또.. 싶어서! 한번 정리를 한 후 다시 돌아오겠습니다.
some에 대해서 알아보기 전에 Opaque type과 generic에 대해 알아보겠습니다.
generic
제네릭을 다루는 시간은 아니니까 간단하게만 살펴보고 넘어가겠습니다!
func swapTwoValues<T>(_ a: inout T, _ b: inout T) {
let temporaryA = a
a = b
b = temporaryA
}
위와 같은 코드가 제네릭 코드입니다.
Type parameter를 이용해서 타입을 지정함으로서 재사용성을 높힐 수 있습니다!
암튼 중요한 것은! 구현부에서는 타입을 지정하지 않고, 호출부에서 선언(사용) 시 타입을 작성해서 알려줍니다.
a = 10
b = 20
var swapValue = swapTwoValues(&a, &b)
위 코드는 제네릭으로 선언한 함수의 사용 예시입니다.
함수 구현 내에서는 실제 값의 타입은 알 수 없고, 함수의 실 사용(호출)하는 외부에서 타입을 알 수 있습니다.
Opaque Type(불투명한 타입)
불투명한 타입은 외부에서 함수의 반환 값 유형을 알 수 없으나, 함수 내부에서는 어떤 타입을 다루는지 알 수 있음.
따라서, Opaque Type은 reverse generic이라고 불리는 거임!
제네릭은 외부에서 타입을 지정하고 내부에선 타입을 알 수 없지만, Opaque Type은 내부에서 타입을 지정하고 외부에서 알 수 없기때문!!
Opaque type은 아래와 같이 사용됩니다.
- 함수의 리턴타입
- Stored, computed property 타입
- Subscripts
- 함수 파라미터 타입
타입들 앞에 some 키워드를 붙여, 프로토콜을 준수하는 어떤 타입(Any)중 하나일 것이라는 뜻으로 사용.
some을 함수 반환 타입으로 사용하여 Opaque Type으로 반환할 수 있습니다.
Protocol을 return type으로 정의해 줄 수 있지만 프로토콜 내부에서 associatedType을 사용했거나, Self 타입을 사용하는 프로토콜이라면 타입 전체가 제네릭하게 되어 반환 타입으로 사용할 수 없다.
때문에 some 키워드를 이용해 불투명한 타입으로 반환해주어야 한다.
명확하지 않은 타입(associatedType/ Self)이 프로토콜 내 정의되고, 이 프로토콜을 반환타입으로 가질 경우, 반환 타입을 불투명 타입(Opaque Type)으로 만들기 위해 사용하는 것임!!!!!
ㅋㅋ 먼말인지 잘 이해가 안되실거라 생각합니다,,, (저도 그럼,, 지금도 헷갈림)
다시 한번 ContentView를 살펴보면서 이야기해 보겠습니다.
프로토콜이 return Type이고, 명확하지 않은 타입을 사용할 경우 some을 이용해 Opaque Type으로 만들어줘야 한다고 했습니다.
struct ContentView: View {
var body: some View {
Text("Hello, world!")
.padding()
}
}
그럼 View는 프로토콜이고, 프로토콜 내부에 associatedType/ Self 이 사용되어, some을 이용해 불투명 타입으로 만들었음을 추측할 수 있겠죠?
다음과 같이 확인할 수 있습니다!
Body는 associatedtype으로 선언되어 있으므로 some을 붙이는 겁니다.
이로써 View 프로토콜을 준수하는 타입을 리턴할 수 있게 되었습니다.
물론 실제 리턴값은 View가 아니라, 작성하는 코드에 따라 달라지겠죠.
(View protocol을 준수하는 타입이 리턴될것임만은 확실함)
만약에 some 이 붙지않는다 가정하면 코드는 다음과 같아집니다…
struct ContentView: View {
var body: VStack<TupleView<Text, Image>> {
VStack {
Text("Hello, world!")
.padding()
Image("pencil")
}
}
}
이런식으로 View에 코드를 추가할 때 마다 일일이 다 추가해줬어야 하는거죠.. (some아 고마워,,)
(컴파일러 고생해..)
이처럼 편의를 위해 사용할 수 있는데, some을 사용함으로서 얻을 수 있는 이점은 크게 2가지입니다.
- 타입 안정성
- 특정 프로토콜을 준수하는 타입을 나타냄 → 프로토콜을 준수하는 특정한 타입만 사용 가능
- 코드의 안정성 증가!
- 가독성, 명확성
- 함수, 프로퍼티의 반환타입이 어느 프로토콜 타입을 준수해야 하는지 명확하게 알 수 있음
- 코드의 가독성과 명확성이 증가.
위 ContentView 예시를 다시 보시면 some을 사용함으로서 View 프로토콜을 준수하는 타입만 리턴값으로 올 수 있으며 반환타입이 View 타입을 준수해야한다는 것을 명확히 확인할수 있습니다.
이처럼 some을 이용해 opaque type을 만들면 자신의 리턴타입을 숨기는 동시에 명확하게 할 수 있습니다.
리턴 값의 실제 타입(underlying type, 추상화 전 구체적인 타입) 은 숨기지만, 어떤 프로토콜을 따르는지 명확하게 할 수 있다는 의미임.
실제 위 코드를 참고해서 보면 사용자 혹은 외부 모듈은 VStack<TupleView<Text, Image>> 와 같은 디테일한 정보를 알 필요가 없음. 이러한 정보를 숨기고 View Protocol 을 따르는 특정 타입(underlying type)만 올 수 있기 때문에 컴파일러는 추론이 가능합니다.
이러한 Opaque Type을 사용하지 않아도 불투명한 타입을 리턴할 수 있습니다.
1) 제네릭 타입에 채택한 프로토콜을 명시하거나, 2) where을 사용하여 체크할 수 있습니다.
물론 가능하지만 생각보다 코드가 복잡해지거나 이해하기 어려워질 수 있죠..
some을 붙혀 Opaque Type으로 리턴하는 것, 프로토콜 타입 리턴하는 것은 무슨 차이??
이 둘의 가장 큰 차이는 리턴 타입의 아이덴티티 보존입니다.
위에서 계속 언급한 것처럼 Opaque Type을 리턴타입으로 사용한다면 하나의 특정 타입만을 리턴할 수 있고, 함수의 호출부에서 Underlying type을 숨길 수 있습니다.(컴파일러는 추론 가능)
프로토콜 타입은 해당 프로토콜을 준수하는 모든 타입이 리턴 가능.
만약 Collection 프로토콜을 리턴타입으로 사용한다면 Array, Dictionary 등을 리턴할 수 있음.
- Protocol Type은 실제 타입(Underlying Type)의 유연성을 높일 수 있음
- Opaque Type은 실제 타입(Underlying Type)을 더 강력하게 보장할 수 있음.
길고 긴 .. 주저리주저리 설명이 끝났습니다..
간단하게 한번 요약해보도록 하겠습니다.
- Opaque Type은 reverse generic 타입이라고 불린다.
- 제네릭은 함수의 구현에서 추상화, 호출부에서 타입 지정.
- Opaque type은 구현에서 구체적 타입 지정, 호출부에서 추상화된 프로토콜 타입 사용
- 외부에 실제, 구체적인 타입(Underlying Type)을 숨길 수 있음
- 캡슐화의 역할, 컴파일러는 추론 가능
- 프로토콜에 명확하지 않은 타입(associated Type/ Self)이 정의 된 경우 프로토콜 타입 사용 불가
- Opaque Type만 사용 가능.
- Opaque Type은 항상 같은 타입을 리턴해야 함.
후… 처음 시작할 때에는 무슨 말인지 이해가 안가서 여러 블로그, 문서를 돌아다니며 겨우,, 어느정도 알게 된 것 같네요… 직접 코딩을 할 때 많이 사용하게 될 내용은 아니라고 생각하지만 무지성 some View를 하지 않고 이제 some이 붙는 이유를 알게되니까 좀 개운하긴 하네요 ㅋㅋ!
그리고 코드를 작성할 경우에 좀 더 생각해볼 수 있는 수가 늘어났기도 하구요. 하나하나 알아가는 재미가 있네요!!
내용을 찾아보면서 some과 any를 비교하는 내용을 한번 봤는데 wwdc 영상이 있더라구요.
이 부분도 다음에 영상 시청 후 한번 정리해 보겠습니다.
(some은 대충 알게 되었으니,, 금방 이해할 수 있지 않을까…그랬으면 좋겠다!)
Embrace Swift generics - WWDC22 - Videos - Apple Developer
Embrace Swift generics - WWDC22 - Videos - Apple Developer
Generics are a fundamental tool for writing abstract code in Swift. Learn how you can identify opportunities for abstraction as your code...
developer.apple.com
다른분들의 글을 읽어보며 작성했지만, 이해가 잘못됐거나 틀린 내용이 보이신다면 얼마든지 지적해주시면 감사하겠습니다!!
SwiftUI) Opaque Type과 Some키워드에 관해서
SwiftUI) Opaque Type과 Some키워드에 관해서
왜 SwiftUI의 첫번째 구문에 var body: some View 인가 에 대해서 궁금했다.
80000coding.oopy.io
SwiftUI) ContentView 이해하기 (1/2) - some View가 뭔가요?
SwiftUI) ContentView 이해하기 (1/2) - some View가 뭔가요?
안녕하세요~ 소들입니다 :> 아침형 인간이 되기 위한 주니어 개발자의 발악 1일차 출근(재택)시간보다 2시간 전에 일어나 운동도 하고 공부도 하는 중이다 이말입니다 하하 1일차 느낀점 일찍 일
babbab2.tistory.com
불투명한 타입 (Opaque Types) | Swift
불투명한 타입 (Opaque Types) | Swift
Last updated 10 hours ago
bbiguduk.gitbook.io
some 과 any
안녕하세요. 저는 왁타버스 뮤직의 검색기능 및 보관함을 개발한 iOS 개발자 함프입니다.
blog.wakmusic.xyz
'iOS > Swift' 카테고리의 다른 글
Concurrency - 기초 (5) | 2024.10.13 |
---|---|
Access Control(접근제어자) (0) | 2024.06.23 |
[weak self] 왜 쓸까!! (1) | 2024.01.15 |
Metatype(.self, .Type, .Protocol) (1) | 2023.11.08 |
Swift Xcode 프로젝트명 바꾸기 (0) | 2023.08.01 |