2024. 9. 17. 23:34ㆍiOS/Swift 문법
Tuist를 통한 모듈화를 하면서 build 최적화에 관심을 가지게 되었다. 그 중에 하나가 static dispatch와 dynamic dispatch이다.
단순하게는 class 선언 시 final을 붙이거나, property에서 private을 붙여 최적화하는 정도만 알았다.
다음의 짧은 아티클을 보면서 Protocol을 통한 type 선언 시, dynamic dispatch가 되는 상황을 알아보자!
Protocol
Swift는 protocol을 통해 기능과 특징을 정의할 수 있다. 아래는 polinator 역할을 protocol로 정의하고, Insect와 Bee가 이 역할을 수행하는 예시이다.
protocol Pollinator {
func pollinate(_ plant: String)
}
struct Hummingbird: Pollinator {
func pollinate(_ plant: String) {
print("\(plant) pollinated by a hummingbird's bill.")
}
}
struct Insect: Pollinator {
func pollinate(_ plant: String) {
print("\(plant) pollinated by an insect's legs.")
}
}
let speedy = Hummingbird()
let busyBee = Insect()
speedy.pollinate("Daisy")
busyBee.pollinate("Marigold")
Generic - Static Dispatch
Generic을 이용하여 polinator를 파라미터로 받아 처리하는 func을 작성할 수 있다.
func polinate<T: Polinator>(_ plants: [String], with pollinator: T) {
for plant in plants {
pollinator.pollinate(plant)
}
}
polinate(["Rose", "Thistle"], with: speedy)
polinate(["Prickly Pear"], with: busyBee)
이 때, Swift는 static dispatch를 이용하여 함수 호출을 최적화한다. 컴파일러는 speed는 HumingBiard type이고 func을 수행할 때, 허밍버드 구현부를 이용해야한다는 것을 안다.
Existential type - Dynamic Dispatch
flexibility를 위해 변수에 specific한 타입이 아닌 any를 이용하여 타입을 지정할 수 잇다.
var anotherPolinator: any Pollinator = Humingbird()
anotherPollinator.pollinate("Dandelion")
anotherPollinator = Insect()
anotherPollinator.pollinate("Dandelion")
// 2
func pollinate2(_ platns: [String], with pollinator: any Pollinator) {
for plant in plants {
pollinator.pollinate(plant)
}
}
polinate2(["Lilly", "Gardenia"], with: anotherPollinator)
이 때는, compile time 때 type을 지워고, run time 때 타입을 결정한다. 즉, dynamic dispatch를 사용한다. 코드의 유연성을 가져갈 수 있지만, 남용하면 dynamic dispatch를 사용하여 성능에 안 좋을 수 있다. 이러한 extra bookeeping으로 인한 memory을 더 점유하기 때문에 static dispatch를 이용하는 generic에 비교해서 덜 효율절이다.
Dependency Injection
우리는 Dependency Injection할 때 protocol을 type으로 사용한다. Test와 Dev, Release에서 다른 결과를 얻기 위함이다. 하지만 Dependency Injection 또한 필요할 때만 적절하게 사용해야하고, trade off가 있을 수 있다는 점을 알고 사용해야한다.
Swift6에서는 이러한 남용을 막고자, 이전에는 protocol을 type으로 사용할 경우, any를 붙이라고 warning만 하였지만, 6.0 이후에는 any를 쓰지 않으면 에러가 발생한다.
'iOS > Swift 문법' 카테고리의 다른 글
복잡한 JSON 디코딩하기 - NestedContainer, custom init (0) | 2024.09.17 |
---|---|
면접 질문: Closure에서 weak self를 사용하지 않아도 되는 경우? (0) | 2024.09.08 |
Map과 FlatMap, CompactMap (0) | 2022.03.21 |
iOS XCTest 코드 (1) (0) | 2022.03.02 |
Class function과 Static function (0) | 2022.02.28 |