[SWIFT] Swift Method Dispatch - Dynamic, Static

2021. 6. 11. 03:29SWIFT

반응형

안녕하세요 :)

저희는 매주 월요일 주간 회의를 진행하는데, 희의를 진행할 때 리더님이 주제를 하나씩 가져와주셔서 대화의 장을 마련해주십니다. (덕분에 많은 것을 배우고 있습니다..) 그래서, 오늘 포스팅을 해 볼 주제가 바로 그 때 얘기했던 주제입니다..!!

 

사실 오늘 회의를 할 때, Method Dispatch에 대해서 들어본 적이 없어서 거의 얘기를 못했는데요 😭

그래서, 회의가 끝나고 혼자서 찾으면서 공부해보았답니다..

 

오늘은 Swift의 Method Dispatch에 대해서 알아보도록 하겠습니다. 

 

Method Dispatch in Swift

우선 Method Dispatch란 Swift에서 여러분들이 Method를 호출할 때, 현재 메모리에서 어떻게 각 메소드를 실행시키고 어떤 메소드를 실행시킬지를 결정지을 때, 사용하는 것(?)이라고 이해하면 좋을 것 같습니다.

 

근데, 무슨 메소드를 어떻게 부를지 결정해(?) 알아서 해주는거 아니야..?!라고 생각할 수 있습니다. 물론 이 Method를 어떻게 부르는지는 알아서 결정해주지만 그 선택권이 개발자에게도 있기 때문에, 이로 인해 성능에 어느정도의 영향을 미칠 수 있습니다.

 

대표적으로 2가지의 타입으로 나뉘는데요. 

Dynamic, Static 이렇게 2가지로 나뉩니다.

 

Static Dispatch

우선 Static Dispatch 방법입니다. 가장 빠른 Dispatch 방법으로 알려져있습니다. 왜냐하면, 컴파일 타임에 컴파일러가 어떤 메소드를 실행할지 주소값을 알고 있기 때문에, 별도의 과정이 필요없고 inline으로 빠르게 수행됩니다. 

 

우선은 빠르다는 것을 알아두면 좋을 것 같습니다. 뒤에 나오는 Dynamic Dispatch도 역시 개발자에 의해 정적패치로 만들어(?)주는 방법들이 있습니다. 좋은 개발 습관을 기를 수 있게 해줄 것 같네요 :)

 

Dynamic Dispatch

보통 많은 OOP를 기반으로 둔 언어가 이 Dispatch 방법을 사용하고 있습니다. 물론 Objective-C 역시도 이 Dispatch 방법을 사용했다고 합니다. 보통 이 방법은 런타임 중에 어떤 메소드를 사용할 지 결정하게 되는데요. 런타임 중에 결정되는만큼 오버헤드가 약간은 발생하고 속도가 느린 방법입니다. 근데 굳이 더 오래걸리는 Dynamic Dispatch 방법을 왜 사용할까요?

 

바로 OOP에서 추구하는 패러다임 때문인 것 같습니다. 다형성(Polymorphism)이라는 개념이 있죠. 이 때, 상속받은 클래스는 부모 클래스의 함수를 override 할 수 있고 그대로 차용해서 사용할 수 있습니다. 그만큼 표현력이 늘게되죠. 이렇게 개발자의 입장에서는 다양하게 표현이 가능하고 더욱 확장성 있는 프로그램을 작성하게 해주는 기능입니다. 하지만, 컴파일러에서는 어떤 모습을 가지고 있는지 어떤 메소드를 호출할 지는 런타임에 결정할 수 있게 됩니다. 그렇기 때문에, 속도는 컴파일 타임에 판단되는 것보다는 느리게 됩니다.

 

+ 메소드들도 포인터로 주소값을 가지고 있다고 합니다. (V-Table이라고 불립니다) 이 때, 런타임 중에 어떤 메소드를 실행할 지 Dispatch를 하는 단계에서 이 포인터를 찾아가면서 어떤 메소드를 실행할 지 결정하게 됩니다. 그렇기 때문에, 위에 말한 절차들이 필요하게 되는 것이죠. OOP에서 Dynamic Dispatch를 이용할 때, 설명하는 좋은 그림이 있는데요. 밑의 그림입니다.

보면 Animal이라는 추상화 된 Super Class의 타입에 각각 Dog, Cat이 할당되어 있는 모습입니다. 그리고 각각 makeNoise()라는 메소드를 호출합니다. 이 때, 런타임 중에 V-Table을 참조해서 어떤 메소드를 호출할 지는 포인터를 따라 가보아야 알 수 있습니다. 바로 그렇기 때문에 위에서 설명했던 시간이 더 걸리는 방법입니다.

 

그리고 다음으로 Dynamic Dispatch에서 Message Dispatch라는 것도 존재합니다. 이 부분은 공부해보니 그동안 사용하면 dynamic, @objc 키워드와 관련된 Dispatch 방법입니다. Swift에서는 Dynamic Dispatch를 위해서 V-Table을 사용하는데 Objective-C에서는 Message Dispatch를 사용한다고 합니다. 즉, 그동안 사용했던 dynamic, @objc는 Objective-C 런타임 중에 사용하기 위해 붙이는 키워드라는 것입니다. (Objective-C 런타임 중에 Dispatch를 하겠다는 뜻이겠죠?)

 

이렇게 크게 2가지의 Dispatch 방법에 대해서 알아보았습니다. 

실제로 Swift에서 Static, Dynamic Dispatch는 어떻게 적용되는지 간단한 코드로 알아보겠습니다.

 

예시

Valu Types

값 타입에서는 상속이 불가능하게 됩니다. 즉, 그렇기 때문에 Static Dispatch 방법이 사용되겠죠.

struct Person {
    func getName() -> String { } // Static
}

extension Person {
    func canJump() -> Bool { } // Static
}

 

Protocol

Protocol에서 makeNoise()의 경우에는 어떤 곳에서 채택하고 있는지를 런타임 중에 확인해야하기에 Dynamic을 extension에서는 protocol을 채택하는 곳과 상관없이 모두 동일하기 떄문에, Static 방법을 사용하게 됩니다.

protocol Animal {
    func makeNoise() -> String // Dynamic
}

extension Animal {
    func hasLegs() -> Bool { } // Static 
}

 

Class

makeNoise()의 경우는 프로토콜을 채택받아서 사용하는 메소드이기 때문에, Dynamic입니다. extension의 경우는 static이겠죠. 그리고 마지막으로 개발자가 명시적으로 Static Dispatch를 만들어 줄 수 있는 방법은 static, final을 붙이는 방법입니다.

class Dog: Animal {
    func makeNoise() -> String { } // Dynamic
    @objc func sleep() { } // Message
}

extension Dog {
    func canBite() -> Bool { } // Static
}

final class Employee {
    func canCode() -> Bool { } // Static
}

 

물론 사소한 부분일 수 있지만, 상속되지 않는 것이 확실한 곳에서는 static, final을 붙여 들이는 습관을 들이면 조금이나마 성능을 개선할 수 있는 습관이지 않을까 싶습니다..!! (모르는 것보다는 알고 있는게 도움이 된다고 생각합니다 🙃)

 

이렇게 오늘은 Swift의 Method Dispatch에 대해서 알아보았습니다. 

혹시 잘못된 정보가 있으면 알려주세요 감사합니다 :)

 

 

레퍼런스

 

Understanding method dispatch in Swift

Static, message, and dynamic dispatch

heartbeat.fritz.ai

 

Static vs Dynamic Dispatch in Swift: A decisive choice

Performance vs Flexibility

medium.com

 

반응형