[Swift] Method Dispatch (2): λ 볡μ‘ν μν©μ Method Dispatch
μΌλ¨ μ 리.. Static Dispatch, Dynamic Dispatch
μ§λ ν¬μ€νΈμμ Static Dispatchμ Dynamic Dispatchλ₯Ό μ 리ν΄λ³΄μλλ°μ, Static Dispatchλ μΈμ€ν΄μ€μμ λ©μλκ° νΈμΆλ λ μ€μ λ‘ μ΄λ€ λ©μλκ° νΈμΆλ μ§ μ»΄νμΌ νμμ κ²°μ ν μ μλ κ²½μ°μμ΅λλ€. κ·Έλ¦¬κ³ Dynamic Dispatchλ λ°νμμ vtableμ΄λΌλ ν μ΄λΈμ μ€μ μ€νν λ©μλμ μ£Όμλ₯Ό μ°Ύμ κ²°μ νλ κ²½μ°μμ΅λλ€.
λ°νμμ ν μ΄λΈμ 룩μ ν΄μΌνλ μ€λ²ν€λ λλ¬Έμ Dynamic Dispatchλ μ±λ₯μλ λΆμ μ μΈ μν₯μ μ€λ€λ κ²λ μ§μ΄λ΄€μμ£ . νμ§λ§ μμκ³Ό λ€νμ±μ μ¬μ©νκΈ° μν΄μλ Dynamic Dispatchμ μ¬μ©μ΄ νμμ μ΄μμ΅λλ€.
κ²°κ΅ μ§λ ν¬μ€νΈμμλ ꡬ쑰체, μ΄κ±°ν λ±, κ° νμ μΈμ€ν΄μ€λ€μ Static Dispatch, μ°Έμ‘° νμ μΈμ€ν΄μ€μΈ ν΄λμ€λ Dynamic Dispatchλ‘ κ²°λ‘ μ΄ λ¬μλλ°μ, μ’ λ 볡μ‘ν μν©μ κ³ λ―Όν΄λ΄ μλ€.
μλ¬Έμ 1: νλ‘ν μ½μ μ±ννλ ꡬ쑰체λ μ΄μ©κ±΄λ°?
μ€μννΈμ μ§μ μ μΈ μμμ ν΄λμ€λ§μ΄ κ°λ₯νμ§λ§, ꡬ쑰체λ‘λ μμμ κ°λ μ μ μ©ν μ μλ λ°©λ²μ΄ μμμ΅λλ€. λ°λ‘ νλ‘ν μ½μ μ¬μ©μ΄μ£ .
class Test {
func printTest() {
print("test")
}
}
class TestA: Test {
override func printTest() {
print("testA")
}
}
class TestB: Test {
override func printTest() {
print("testB")
}
}
let tests = [Test(), TestA(), TestB()]
for test in tests {
print(type(of: test))
test.printTest()
}
μ§λ ν¬μ€νΈμμ μ¬μ©νλ μ΄ ν΄λμ€λ€μ ꡬ쑰체μ νλ‘ν μ½λ‘ λ°κΏλ³Όκ²μ!
protocol TestPrintable {
func printTest()
}
struct Test: TestPrintable {
func printTest() {
print("test")
}
}
struct TestA: TestPrintable {
func printTest() {
print("testA")
}
}
struct TestB: TestPrintable {
func printTest() {
print("testB")
}
}
let tests: [TestPrintable] = [Test(), TestA(), TestB()]
for test in tests {
test.printTest()
}
μ΄λ κ² νλ©΄ λμΌν μΆλ ₯μ΄ λμ€κ² μ£ ? μ΄μ tests λ°°μ΄μ μμ νμ μ νλ‘ν μ½μ νμ μΈ TestPrintableμ΄ λκ² λ€μ.
μ, κ·ΈλΌ λ€μ μλ¬Έμ μ΄ μκΉλλ€. νλ‘ν μ½λ§ λ³΄κ³ μ€μ ꡬνμ²΄κ° λμ§ μ΄λ»κ² μμ..?
μ»΄νμΌ νμμλ TestPrintableμ μ μΈλ§ μκ³ μκ³ , μ μλ₯Ό μ°Ύμκ°λ €λ©΄ κ° μΈμ€ν΄μ€κ° κ°μ§ λ©μλ μ μλ₯Ό μ°Ύμκ°μΌκ² μ£ ? κ²°κ΅ μ΄λ²μλ Dynamic Dispatchκ° λκ² λ€μ.
νλ‘ν μ½μ μ±νν ꡬ쑰체μ Dynamic Dispatch
ꡬ쑰체λ vtableμ μΈ κ² κ°μ§λ§, κ·Έλ μ§ μμ΅λλ€. ꡬ쑰체λ 곡ν΅μ‘°μμΈ μΈμ€ν΄μ€κ° μμΌλκΉμ.
κ·Έλμ μ΄λ²μλ μλ‘μ΄ ν μ΄λΈμΈ Protocol Witness Table(PWT)μ΄ μ¬μ©λ©λλ€.
Protocol Witness Tableμ νλ‘ν μ½μ μ±ννλ κ° κ΅¬μ‘°μ²΄ μΈμ€ν΄μ€κ° νλμ© κ°μ§κ³ , νΉμ ν λ©μλμ λν μ€μ ꡬνμ μ΄ ν μ΄λΈμ μ°κ²°μμΌλ‘λλ€.
WWDCμμ λ°νν μλ£μμλ μ΄λ κ² νννκ³ μμ΄μ. λ°°μ΄μ λ΄κΈ΄ μΈμ€ν΄μ€λ€μ΄ λ΄λΆμ PTWλ₯Ό κ°μ§κ³ μ¬κΈ°μ μ€μ ꡬνμ λν λ§ν¬κ° λ§λ€μ΄μ Έ μλ κ²μ΄μ£ .
μ΄λ κ² νλ©΄ λ°νμμ λ°°μ΄ μμκ° κ°μ§ ν μ΄λΈμ ν λ² μ½μ΄μ μ½λλ₯Ό μ°Ύμκ°μΌνλ Dynamic Dispatchκ° λκ² μ£ !
μλ¬Έμ 2: νλ‘ν μ½μ Extension ν΄μ λ©μλκ° μ μλμ΄ μλ€λ©΄?
μ΄λ° κ²½μ°λ μ΄λ¨κΉμ?
protocol TestPrintable {
}
extension TestPrintable {
func printTest() {
print("hello")
}
}
struct Test: TestPrintable {
func printTest() {
print("test")
}
}
struct TestA: TestPrintable {
func printTest() {
print("testA")
}
}
struct TestB: TestPrintable {
func printTest() {
print("testB")
}
}
let tests: [TestPrintable] = [Test(), TestA(), TestB()]
for test in tests {
test.printTest()
}
νλ‘ν μ½μ extensionν΄μ κΈ°λ³Έ λ©μλλ₯Ό μ μν΄λκ³ μ€νμ ν΄λ³΄μμ΅λλ€.
κ²°κ³Όλ,
hello
hello
hello
μ΄λ κ² κΈ°λ³Έ λ©μλκ° μ€νλ©λλ€. μλνλ©΄ λ°°μ΄μ μμ νμ μ΄ TestPrintableμ΄κΈ° λλ¬Έμ μ΄ νμ μ λν λ©μλκ° κ³§λ°λ‘ μ€νλλ κ²μ΄μ£ . κ° μΈμ€ν΄μ€μ μ μλ printTestλ νλ‘ν μ½λ‘λΆν° μ±νλ°μ λ©μλκ° μλλλ€.
μ€μ λ‘ XCodeμμ μλμμ±λ μ§μν΄μ£Όμ§ μλ€μγ γ
μλλ μ΄λ κ² ν΄μ€μΌνλλ° λ§μ΄μ£ ..
μ¦, μ΄λ° κ²½μ°λ μΈμ λ νλ‘ν μ½μ κΈ°λ³Έ λ©μλλ₯Ό μ€ννλ Static Dispatchλ‘ λμν©λλ€.
μλ¬Έμ 3: νλ‘ν μ½μ μΈν°νμ΄μ€κ° μκ³ , κΈ°λ³Έ λ©μλκ° ExtensionμΌλ‘ μ μλ κ²½μ°λ?
μμ μμμμ μΈν°νμ΄μ€λ§ μΆκ°ν΄λ³΄κ² μ΅λλ€.
protocol TestPrintable {
func printTest()
}
extension TestPrintable {
func printTest() {
print("hello")
}
}
struct Test: TestPrintable {
func printTest() {
print("test")
}
}
struct TestA: TestPrintable {
func printTest() {
print("testA")
}
}
struct TestB: TestPrintable {
func printTest() {
print("testB")
}
}
let tests: [TestPrintable] = [Test(), TestA(), TestB()]
for test in tests {
test.printTest()
}
μ΄λ²μλ νλ‘ν μ½μ μΈν°νμ΄μ€κ° μ‘΄μ¬νκ³ , μ΄λ₯Ό μ±ννλ ꡬ쑰체μμ κ°κ° μμ μ ꡬν체λ₯Ό κ°μ§κ³ μμ΅λλ€. μ΄λ° κ²½μ°μ μ½λλ₯Ό μ€νν΄λ³΄λ©΄ κ²°κ³Όλ μλμ²λΌ λμ€λλ°μ,
test
testA
testB
μ΄λ²μλ νλ‘ν μ½μ μ±νν μΈμ€ν΄μ€λ€μ λ©μλκ° μ€νλ©λλ€. κ° λ©μλλ€μ΄ νλ‘ν μ½μ λ°μ ꡬ쑰체μμ μ μλκ³ μλ μν©μ΄κΈ° λλ¬Έμ μ΄λ° κ²½μ°λ νλ‘ν μ½μ μ±νν ꡬ쑰체μ λ©μλκ° μ°μ μ μΌλ‘ μ€νλ©λλ€.
λ°λΌμ μ΄λ° κ²½μ°λ Dynamic Dispatch μ λλ€.
μλ¬Έμ 4: ν΄λμ€μ Extensionμ?
μ΄λ²μ ν΄λμ€λ₯Ό Extensionνλ κ²½μ°μ λλ€.
class Test {
func printTest() {
print("test")
}
}
extension Test {
func printExtension() {
print("extension")
}
}
class TestA: Test {
override func printTest() {
print("testA")
}
override func printExtension() {
print("extensionA")
}
}
class TestB: Test {
override func printTest() {
print("testB")
}
}
let tests = [Test(), TestA(), TestB()]
for test in tests {
test.printExtension()
}
μ΅μμ ν΄λμ€μ Extensionμ μλ‘μ΄ λ©μλ μΆκ°νκ³ TestAμμ μ€λ²λΌμ΄λ©μ νλ €κ³ ν©λλ€.
νμ§λ§ μ΄λ κ² μλ¬κ° λ©λλ€.. ExtensionμΌλ‘ λ§λ λ©μλλ μ€λ²λΌμ΄λ©μ΄ λΆκ°λ₯νλ€κ³ νλ€μ.. Objective-C λ°νμμ μ¬μ©νλ©΄ κ°λ₯νλ€κ³ ν©λλ€.
λ§μ½ Objective-C λ°νμμ μ¬μ©νμ§ μλλ€λ©΄ νμ μ΅μμ ν΄λμ€μ λ©μλλ§ μ¬μ©ν μ μμΌλ―λ‘ Static Dispatch κ° λ©λλ€.
μ 리
https://www.rightpoint.com/rplabs/switch-method-dispatch-table
μ΄ κΈμ νλ‘ μ μ 리λμ΄ μμ΄μ κ·Έλλ‘ κ°μ Έμλ΄ λλ€!
- 1) κ° νμ : μμν κ° νμ , νλ‘ν μ½μ μ±ννμ§ μλ ꡬ쑰체λ enumμ νμ Static Dispatchμ λλ€. μ΄λ€ λ©μλλ₯Ό μ€ννμ§λ λ무λ λͺ ννλκΉμ!
- 2) νλ‘ν μ½: νλ‘ν μ½μ μ±ννλ νμ λ€μ κΈ°λ³Έμ μΌλ‘ Dynamic Dispatchμ λλ€. μ¬κΈ°μ μ¬μ©νλ ν μ΄λΈμ Protocol Witness Table μ΄κ΅¬μ. νμ§λ§ Protocolμ μΈν°νμ΄μ€μ ν¬ν¨λμ§ μλ κΈ°λ³Έ λ©μλλ€μ νμ κΈ°λ³Έ λ©μλκ° νΈμΆλκΈ° λλ¬Έμ Static Dispatch μ λλ€.
- 3) ν΄λμ€: ν΄λμ€λ λ€νμ±κ³Ό μμ λλ¬Έμ κΈ°λ³Έμ μΌλ‘ Dynamic Dispatchμ΄κ³ , vtableμ μ΄μ©ν΄μ λ©μλλ₯Ό μ€νν©λλ€. ν΄λμ€μ extensionμΌλ‘ μ μλ λ©μλλ Objective-C λ°νμμ μ¬μ©νμ§ μμΌλ©΄ μ€λ²λΌμ΄λ©ν μ μκΈ° λλ¬Έμ Static Dispatch μ λλ€.
Reference
- https://developer.apple.com/videos/play/wwdc2016/416/
- https://babbab2.tistory.com/144?category=828998
- https://www.rightpoint.com/rplabs/switch-method-dispatch-table
- https://zeddios.tistory.com/597