본문 바로가기

iOS

Static dispatch, Dynamic dispatch

728x90
반응형
SMALL

Static dispatchDynamic dispatch는 Swift에서 함수 호출 시 메소드가 결정되는 방식을 설명하는 용어입니다.

Static dispatch

컴파일 시간에 메소드 호출을 처리하는 방식입니다.

컴파일러는 함수 호출이 해당하는 메소드를 직접 참조하여 호출을 처리합니다. 이 방식은 컴파일 시간에 메소드 호출 결정이 이루어지기 때문에 실행 시간에 오버헤드가 거의 발생하지 않습니다. 그러나 이 방식은 함수 호출 시 메소드가 무조건 호출되는 것이기 때문에 동적으로 호출될 수 없으며, 다형성(polymorphism)을 지원하지 않습니다.

class Animal {
    func makeSound() -> String {
        return ""
    }
}

class Dog: Animal {
    override func makeSound() -> String {
        return "Woof!"
    }
}

class Cat: Animal {
    override func makeSound() -> String {
        return "Meow!"
    }
}

let dog = Dog()
let cat = Cat()

print(dog.makeSound()) // Output: "Woof!"
print(cat.makeSound()) // Output: "Meow!"

위 코드에서 Dog와 Cat 클래스가 Animal 클래스를 상속하고 있습니다. Animal 클래스의 makeSound() 메서드는 기본적으로 빈 문자열을 반환하도록 정의되어 있습니다. 하지만 Dog와 Cat 클래스에서는 이 메서드를 오버라이드하여 각자의 소리를 반환하도록 재정의하고 있습니다.

그리고 마지막으로 dog와 cat 인스턴스를 생성하여 각자의 소리를 출력하고 있습니다. 이때 dog.makeSound()와 cat.makeSound() 호출은 컴파일 타임에 각각 Dog와 Cat 클래스의 makeSound() 메서드로 정적 바인딩(Static Dispatch)됩니다.

 

Dynamic dispatch

런타임에 메소드 호출을 처리하는 방식입니다.
컴파일러는 함수 호출이 해당하는 메소드를 직접 참조하지 않으며, 함수 호출 시 객체의 타입 정보를 참조하여 해당 객체에 적합한 메소드를 동적으로 호출합니다. 이 방식은 다형성을 지원하며, 실행 시간에 동적으로 호출될 수 있기 때문에 불필요한 메소드 호출이 발생할 수 있어 오버헤드가 있을 수 있습니다. 그러나 이 방식은 컴파일 시간에는 메소드 호출 결정이 이루어지지 않기 때문에 실행 시간에 다양한 타입의 객체를 처리할 수 있어 유연성이 높습니다.

class Animal {
    func makeSound() -> String {
        return ""
    }
}

class Dog: Animal {
    override func makeSound() -> String {
        return "Woof!"
    }
}

class Cat: Animal {
    override func makeSound() -> String {
        return "Meow!"
    }
}

let dog = Dog()
let cat = Cat()

let animals: [Animal] = [dog, cat]

for animal in animals {
    print(animal.makeSound())
}

위 코드에서 Dog와 Cat 클래스, 그리고 Animal 클래스는 Static Dispatch 예제 코드와 같습니다. 그리고 마지막으로 dog와 cat 인스턴스를 배열에 저장하고, 반복문을 사용하여 각 인스턴스의 makeSound() 메서드를 호출하고 있습니다.

이때 배열은 Animal 타입으로 선언되었기 때문에 컴파일 타임에는 makeSound() 메서드의 실제 구현이 어떤 것인지 알 수 없습니다. 따라서 이 호출은 런타임에 해당 인스턴스의 실제 타입에 맞는 makeSound() 메서드로 동적 바인딩(Dynamic Dispatch)됩니다.

 

iOS에서는 Dynamic dispatch 일반적으로 사용되며, Objective-C에서는  방식이 표준 방식입니다. Swift에서도 Dynamic dispatch 사용할  있으며 방식은 특히 다형성이 필요한 경우에 사용됩니다그러나 Swift Static dispatch 지원하기 때문에컴파일 시간에 호출 결정이 이루어져야 하는 성능이 중요한 경우에는 Static dispatch 사용할  있습니다.

 

*** 다형성 ****

다형성(polymorphism)이란 객체 지향 프로그래밍에서 여러 객체들이 동일한 메시지를 수신할 때 각 객체들이 그 메시지에 대해 서로 다른 방식으로 동작하는 능력을 의미합니다. 이를 통해 코드 재사용성과 유지보수성이 향상되며, 객체 지향의 핵심 개념 중 하나입니다.

iOS에서도 객체 지향 프로그래밍이 사용되므로 다형성 개념이 적용됩니다. 다형성을 구현하는 방법으로는 오버라이딩(overriding)과 프로토콜(protocol)이 있습니다.

오버라이딩은 상속받은 메서드를 자식 클래스에서 재정의하여 사용하는 것입니다. 이를 통해 부모 클래스와 자식 클래스에서 같은 메서드를 호출해도 각각의 클래스에서 정의된 메서드가 호출됩니다.

프로토콜은 인터페이스와 유사한 역할을 합니다. 프로토콜을 채택한 클래스나 구조체는 프로토콜에서 정의한 메서드를 구현해야 하며, 이를 통해 프로토콜을 준수하는 객체들을 하나의 타입으로 다룰 수 있습니다. 이는 객체 지향 프로그래밍에서 인터페이스를 구현하는 것과 유사합니다.

다음은 오버라이딩과 프로토콜을 통한 다형성 예시 코드입니다.

// 오버라이딩 예시
class Animal {
    func makeSound() {
        print("Animal makes a sound")
    }
}

class Dog: Animal {
    override func makeSound() {
        print("Dog barks")
    }
}

class Cat: Animal {
    override func makeSound() {
        print("Cat meows")
    }
}

let animals: [Animal] = [Animal(), Dog(), Cat()]

for animal in animals {
    animal.makeSound()
}

 

// 프로토콜 예시
protocol Vehicle {
    func drive()
}

class Car: Vehicle {
    func drive() {
        print("Car drives")
    }
}

class Bicycle: Vehicle {
    func drive() {
        print("Bicycle rides")
    }
}

let vehicles: [Vehicle] = [Car(), Bicycle()]

for vehicle in vehicles {
    vehicle.drive()
}

 

728x90
반응형
LIST

'iOS' 카테고리의 다른 글

(iOS) Chat GPT 사용해보기  (0) 2023.04.12
컬렉션 뷰에서 데이터를 사용할 때 struct?, class?  (0) 2023.04.11
iOS APP 화면 구성  (0) 2023.04.11
NSObject  (0) 2023.04.11
ARC(Automatic Reference Counting)  (0) 2023.04.11