728x90
개요
- 기본적으로 객체지향 패러다임이 적용되어있는 언어들은 메소드와 프로퍼티들의 오버라이드를 지원한다.
- 이렇게 오버라이드된 메소드들이 호출될 때, 프로그램의 입장에선 실제 호출할 함수가 상위 클래스의 메소드인지 아니면 현재 클래스의 메소드인지 의사결정하는 과정이 필요하다.
- 해당 의사결정 타입은 Static Dispatch와 Dynamic Dispatch가 있다.
import UIKit
class Parent {
var name: String = "Parent"
func printAge() {
print("My Age is 15")
}
}
class Child: Parent {
override var name: String {
get {
return "Child"
}
set {
super.name = newValue
}
}
override func printAge() {
print("My Age is 13")
}
}
let p: Parent = Child()
p.printAge()
print(p.name)
/* 1. Static Dispatch
My Age is 15
Parent
*/
/* 2. Dynamic Dispatch (Swift의 결과)
My Age is 13
Child
*/
Static Dispatch (Direct Call)
- 변수의 명목상 타입에 맞추어 함수를 호출한다.
- 컴파일 시에 어떤 것을 호출할지가 결정된다.
- 현재 Parent 클래스 타입으로 선언되어있다면 Parent 클래스의 함수를 호출하게 된다.
- Child 클래스의 요소를 호출하고 싶다면 타입 캐스팅을 활용해야한다.
- 따라서 객체지향의 다형성을 활용하기 어려워지는 방식이다.
Dynamic Dispatch (Indirect Call)
- 변수의 실제 타입에 맞추어 함수와 프로퍼티를 호출한다.
- 런타임 시에 어떤 것을 호출할지가 결정된다.
- 어떤 서브클래스가 들어와도 실제 타입에 맞는 요소를 호출한다.
- 다형성 활용에 유리하다.
- 하지만 런타임 시에 실제 참조할 요소를 찾는 과정이 필요하여 Static Dispatch에 비해 O(1)의 시간복잡도가 더 소모되어 속도면에선 불리하다.
- 때문에 최적화 시에 가능하다면 Static Dispatch를 활용할 수 있도록 해야한다.
- Swift는 Dynamic Dispatch를 차용한다.
Dynamic Dispatch가 필요하지 않은 경우의 최적화 가능한 방법
- 오버라이드 될 필요가 없는 요소들은 final 키워드를 붙인다.
- 컴파일러는 final 키워드를 보고 오버라이드 될 필요가 없는 요소라는 것을 알고 최적화 하게 된다.
- private 키워드를 붙이면 해당 요소는 한 파일 내에서만 참조되는 것이 보장된다.
- 따라서 해당 요소에 대한 오버라이드가 파일 내에 존재하지 않는다면 자동으로 컴파일러가 Direct Call로 바꾸어 준다.
- WMO(Whole Module Optimization)을 사용한다면 internal 선언만으로 Direct Call을 보장할 수 있음
- 다만 모듈 내에서 오버라이드가 없는 경우에 한해서이다.
- swift에선 모듈을 이루는 파일들을 개별적으로 컴파일하기 때문에 다른 파일에서 오버라이딩이 일어났는지 알 수 없지만 모듈은 모듈 통째로 컴파일을 하기 때문에 모듈 내에서 internal선언을 하게 되면 다른 모듈에선 오버라이딩이 불가능하다는 것을 확인해준다.
728x90
'Swift' 카테고리의 다른 글
[Swift] Property Wrapper (0) | 2022.02.13 |
---|---|
[Swift] self vs Self (0) | 2021.12.08 |
[Swift] 클로저 (Closure) (0) | 2021.07.12 |
[Swift] Any, AnyObject (0) | 2021.06.21 |
[Swift] defer (0) | 2021.06.21 |
댓글