관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] Static Dispatch, Dynamic Dispatch 성능 최적화 방법, Witness Table, (final, private을 사용하는 이유) 본문

iOS 기본 (swift)

[iOS - swift] Static Dispatch, Dynamic Dispatch 성능 최적화 방법, Witness Table, (final, private을 사용하는 이유)

jake-kim 2021. 12. 24. 01:39

final class vs class

final class A {
  ...
}
class B {
  ...
}
  • class A와 class B의 차이점
    • A는 서브클래싱이 불가능
    • A는 성능적으로 더욱 높은 장점 -> 성능이 좋은 이유?
  • 성능이 좋은 이유 - static dispatch 사용 (아래에서 이어서 개념 설명)

Static Dispatch (Direct Call)

  • 변수를 타입에 맞춰서 메소드와 프로퍼티를 참조
  • 참조될 요소를 컴파일 타임에 결정
  • 상속 가능성이 없다는 keyword를 코드에 표출하면 컴파일러는 Static Dispatch를 사용

Dynamic Dispatch (Indirect Call)

  • override, subclass와 같은 변수의 실제 타입의 맞춰서 메소드와 프로퍼티를 호출
    • 대표적으로 객체지향 프로그래밍에서 `다형성`에서 Dynamic Dispatch로 접근
  • 런타임에 참조할 요소를 O(1)의 시간 복잡도를 가지고 찾는 과정이 존재

성능 최적화를 위해 Static Dispatch를 사용

  • override가 필요없는 요소들에는 final 키워드 사용
    • 컴파일러는 Static Dispatch로 접근
  • private 키워드를 붙여서 선언할 것
    • private을 가진 해당 요소는 한 블럭 내에서만 참조되는 것이 보장되고 한 블럭내에 오버라이드가 없는 경우 컴파일러가 이것을 Static Dispatch로 접근
  • class보다는 Struct와 enum을 사용
    • 서브클래싱이 불가능한 Value Type을 사용하여 Static Dispatch가 이루어지도록 설계
    • Reference Type은 오버라이딩이 되지 않는다는 명시적인 키워드를 사용하면(final, private) Static Dispatch지만 나머지는 Dynamic Dispatch를 사용

Protocol은 Dynamic Dispatch를 사용

  • Protocol은 구현체를 제공하지 않으므로, 런타임 시에 구현체를 참조하기 위해서 Dynamic Dispatch를 사용

Extension에서의 Dispatch

  • Value Type에서의 extension을 사용하면, 상속 가능성이 없기 때문에 Static Dispatch 수행
    struct SomeStruct {
      func someFunction() { ... }
    }
    
    extension SomeStruct {
      func someAnotherFunction() { ... }
    }​
  • Class Type에서의 extension 사용
    • extension은 본래 메소드 오버라이딩이 불가능하므로 Static Dispatch 수행
      struct SomeClass {
        func someFunction() { ... }
      }
      
      extension SomeStruct {
        func someFunction() { ... } // 컴파일 에러! (오버라이딩 불가)
      }​
  • Protocol에서의 extension 사용
    • 기본 지식 - Witness Table이란?
      • 프로토콜을 통해 호출하는 메소드는 프로토콜을 채택한 타입들이 실제로 구현한 메소드이므로, 프로토콜 타입의 참조로만 구현체의 내용을 사용할 때 사용되는 프로토콜이 보유한 정보를 `Witness Table`이라 명칭
    • Default Implementation (본체에 선언된 멤버 구현): 서브 클래스들이 메소드들을 구현하고 있음이 보장되므로, Witness table을 이용한 Dyanamic Dispatch 수행
      protocol SomeProtocol {
        func someFunction() 
      }
      
      extension SomeProtocol {
        func someFunction() { ... }
      }​
    • 본체에 선언되지 않았으므로, 본체가 보유한 Witness Table을 사용하지 못하므로 Static Dispatch 수행
      protocol SomeProtocol {
        func someFunction() 
      }
      
      extension SomeProtocol {
        func someAnotherFunction() { ... }
      }​

 

* 참고

- WWDC 2016 (Withness Table 내용): https://developer.apple.com/videos/play/wwdc2016/416/

- Increasing performance by reducing dynamic dispatch: https://developer.apple.com/swift/blog/?id=27

Comments