컴파일 타임에 함수의 메모리 주소를 직접적으로 삽입하거나, 함수 명령코드를 해당위치에 직접적으로 심어버리는 것 (in-line)
사용 시점
벨류타입(구조체/열거형)에 사용
프로토콜타입으로 정의되었을 때 본체의 요구사항에 대해서는 Table Dispatch -Witness Table으로 저장되지만 프로토콜 본체의 요구사항에는 없으면서 확장으로 기본 구현된 메서드는 Direct Dispach (프로토콜을 채택해서 다형성이 가능해지는 값타입의 경우 메서드가 다양하게 실행될 수 있음!)
상속/다형성의 장점을 누릴 수 없다. (상속으로 될 수 없으니 당연히 다형성 불가)
*다형성 - 하나의 객체(인스턴스)가 다양한 형태로 저장될 수 있음. 클래스 타입, 부모 타입, 프로토콜 타입으로도 저장될 수 있음. 하나의 메서드나 클래스를 다양하게 동작 가능 (상속 → 오버라이딩)
but, 원래는 값타입인 것도 프로토콜을 채택함으로써 다형성이 가능해지는 것도 있다
🌸 코드예시
```swift
struct MyStruct {
func method1() { print("Struct - Direct method1") } //10-20
func method2() { print("Struct - Direct method2") } //30-40
}
let struct = MyStruct()
struct.method1() // 10 : 여기 코드에다가 실행되어야할 코드 영역의 메모리 주소(명령어 주소)를 바로 삽입해놓거나, 명령코드를 직접적으로 심어버린다
struct.method2() // 30
```
2.Table Dispatch (동적/Dynamic Dispatch)
런타임에(실제 앱이 실행되는 와중에 찾아서) 실행
런타임에 일어나기 때문에 성능상 손해를 볼 수 있다.
함수의 포인터(메모리 주소에 대한 정보)를 배열형태(table)로 보관후 런타임에 실제로 주소(코드 영역에 묶음으로 있는)를 찾아가서 실행
사용 시점 ( 클래스, 프로토콜 - *어떤 타입으로 저장했는지도 중요)
클래스의 메서드는 Virtual Table 형태로 저장 - 클래스 타입으로 저장한 인스턴스에 대해 메서드를 실행했을 때
프로토콜에서 본체의 요구사항에 있는 것은 Witness Table 형태로 저장 - 프로토콜 타입으로 저장한 인스턴스에 대해 메서드를 실행했을 때
프로토콜 본체의 요구사항에 정의된 메서드에 대해서는 Witness Table 형태로 저장하지만
프로토콜 본체의 요구사항에 정의되지 않은 메서드에 대해서 extension에서 기본 구현된 메서드는 Direct Dispach 형태로 저장한다
🌸 코드예시
```swift
class FirstClass { //Table Dispatch - Virtual Table : [110, 120]
func method1() { print("Class - Table method1") } //코드 영역 110 - 119
func method2() { print("Class - Table method2") } //코드 영역 120 - 129
}
// 자식클래스에서 테이블을 따로 보유
class SecondClass: FirstClass { //Table Dispatch - Virtual Table : [110, 130, 140]
override func method2() { print("Class - Table method2-2") } //코드 영역 130-139
func method3() { print("Class - Table method3") } //코드 영역 140-149
}
let first = FirstClass()
first.method1() //110 으로 가서 실행
first.method2() //120 으로 가서 실행
let second = SecondClass()
second.method1() //110 으로 가서 실행
second.method2() //130 으로 가서 실행 (재정의된 것)
second.method3() //140 으로 가서 실행 (상속 후 새로운 메서드)
```
```swift
protocol MyProtocol { //Table Dispatch - Witness Table : [210, 220]
func method1() // 요구사항 - 코드 영역 210 - 219
func method2() // 요구사항 - 코드 영역 220 - 229
}
extension MyProtocol {
// 요구사항의 기본 구현 제공 ==> Witness Table : [210, 220]
func method1() { print("Protocol - Witness Table method1") }
func method2() { print("Protocol - Witness Table method2") }
// 필수 요구사항은 아님 ==> Direct Dispatch
func anotherMothod() {
print("Protocol Extension - Direct method")
}
}
class FirstClass: MyProtocol {
func method1() { print("Class - Virtual Table method1") }
func method2() { print("Class - Virtual Table method2") }
func anotherMothod() { print("Class - Virtual Table method3") }
}
let first = FirstClass()
//클래스 타입으로 저장 => Virtual Table
first.method1() // Class - Virtual Table method1
first.method2() // Class - Virtual Table method2
first.anotherMothod() // Class - Virtual Table method3
let proto: MyProtocol = FirstClass()
//프로토콜 타입으로 저장 =>
// 본체 필수 요구 사항에 있는 건 Witness Table
// 본체 필수 요구 사항에 없으면서확장으로 기본 구현된건 Direct method
//⭐️ But, FirstClass에서 프로토콜 채택하고 메서드들을 재구현해주었기 때문에 Witness Table이 아닌 Virtual Table로 저장/실행된다
//⭐️ 만약, FirstClass에서 프로토콜 채택하고 메서드들을 재구현해주지 않았다면 Witness Table 형태로 저장/실행되었겠지
proto.method1() // Class - Virtual Table method1
proto.method2() // Class - Virtual Table method2
proto.anotherMothod() // Protocol Extension - Direct method 여기에바로 명령어 주소를 삽입하거나 명령어를 삽입
```
3.Message Dispatch
런타임(실제 앱이 실행되는 와중에 찾아서 실행)
objective-C에서 사용하던 방식
상속 후 재정의하지 않는 메서드는 상위 클래스를 참조 하고 있음 (각각 포인터를 가지고 있는게 아니라)
1.Direct Dispatch (직접/Static Dispatch)
컴파일 타임에 함수 실행
컴파일 타임에 함수의 메모리 주소를 직접적으로 삽입하거나, 함수 명령코드를 해당위치에 직접적으로 심어버리는 것 (in-line)
사용 시점
상속/다형성의 장점을 누릴 수 없다. (상속으로 될 수 없으니 당연히 다형성 불가)
🌸 코드예시
2.Table Dispatch (동적/Dynamic Dispatch)
런타임에(실제 앱이 실행되는 와중에 찾아서) 실행
함수의 포인터(메모리 주소에 대한 정보)를 배열형태(table)로 보관후 런타임에 실제로 주소(코드 영역에 묶음으로 있는)를 찾아가서 실행
사용 시점 ( 클래스, 프로토콜 - *어떤 타입으로 저장했는지도 중요)
🌸 코드예시
3.Message Dispatch
🌸 코드예시