iOS 응용 (SwiftUI)

[iOS - SwiftUI] generic과 opaque type 차이, some view와 protocol 반환의 차이 (#opaque types, #existential types)

jake-kim 2024. 8. 5. 01:04

generic과 opaque type 개념

  • generic은 타입의 유연성을 제공하여 사용하는쪽에서 타입을 정하게끔하는 방법

ex) generic을 사용하는 가장 대표적인 예제 - Stack 구현

struct Stack<Element> {
    private var elements: [Element] = []
    
    mutating func push(_ element: Element) {
        elements.append(element)
    }
    
    mutating func pop() -> Element? {
        elements.popLast()
    }
    
    func peek() -> Element? {
        elements.last
    }
    
    func isEmpty() -> Bool {
        elements.isEmpty
    }
}
  • opaque type은 구현부에서는 타입이 구체적인 타입을 사용하지만, 반환 타입은 감추는 것

ex) SwiftUI에서는 opaque type인 some 키워드를 사용하여 View를 반환하는 body 프로퍼티가 존재

struct ContentView: View {
    var body: some View {
        VStack {
            Text("Hello, World!")
                .font(.largeTitle)
                .padding()
        }
    }
}

generic과 opaque 타입의 차이

  • generic은 사용하는 쪽에서 타입을 결정하고, 컴파일러 최적화가 opaque 타입보다 떨어짐
  • opaque 타입은 정의하는 쪽에서 타입이 구체적인 타입을 사용하게되며 컴파일러가 미리 알 수 있으므로 최적화가 가능

opaque 타입과 protocol을 반환하는 것의 차이

  • 단순 protocol을 반환하는것은 dynamic dispatch를 사용하며, opaque 타입을 반환하면 static dispatch가 되므로 최적화에 더욱 유리

ex) opaque 타입에 분기문을 넣어서 동적으로 concrete 타입이 정해지게 만들면 컴파일 에러가 발생

protocol SomeProtocol {}

struct A: SomeProtocol {}
struct B: SomeProtocol {}

func someFunc1() -> SomeProtocol {
    if Bool.random() {
        A()
    } else {
        B()
    }
}

func someFunc2() -> some SomeProtocol {
    if Bool.random() {
        A() // error: Branches have mismatching types 'A' and 'B'
    } else {
        B()
    }
}

* 참고: https://medium.com/kerege/swift-concepts-opaque-types-existential-types-93326a3e55df