정보/레벨 1

iOS에서 델리게이트 패턴(Delegate Pattern)은 어떤 목적으로 사용되나요?

밤새는 탐험가89 2024. 8. 23. 11:25

1. 델리게이트 패턴(Delegate Pattern)의 목적

 델리게이트 패턴은 어떤 객체의 행동을 다른 객체에 위임하기 위해 사용되는 패턴이에요. iOS에서 자주 사용되며, 특정 객체가 해야 할 일을 다른 객체가 대신 처리하도록 할 수 있어요. 이를 통해 코드의 재사용성을 높이고, 객체 간의 결합도를 낮출 수 있죠.

 

예시:

 

예를 들어, Car라는 클래스가 있다고 해볼게요. 이 클래스는 엔진을 켤 수 있어요. 그런데 엔진이 켜질 때마다 누군가에게 이 사실을 알리고 싶다면, 그 알림 로직을 Car 클래스 안에 다 넣지 않고, 다른 객체에게 그 일을 맡길 수 있어요. 여기서 델리게이트 패턴을 사용하면 이런 식으로 구현할 수 있어요

 

protocol CarDelegate {
    func engineDidStart()
}

class Car {
    var delegate: CarDelegate?

    func startEngine() {
        print("엔진이 켜졌습니다")
        delegate?.engineDidStart()
    }
}

class Driver: CarDelegate {
    func engineDidStart() {
        print("운전자가 알림을 받았습니다: 자동차 엔진이 켜졌어요!")
    }
}

let myCar = Car()
let driver = Driver()

myCar.delegate = driver
myCar.startEngine()

 

이 예시에서는, 자동차의 엔진이 켜지면 Driver가 델리게이트로서 그 사실을 알림받아요.

 

2. 델리게이트 패턴과 콜백 함수의 차이점

콜백 함수와 델리게이트 패턴은 둘 다 비슷한 역할을 해요. 어떤 작업이 끝났을 때 알림을 받는 방법이에요. 하지만 두 가지 주요 차이점이 있어요.

  • 콜백 함수는 특정 작업이 끝났을 때 함수 자체가 호출되는 방식이에요. 간단하고, 작은 작업을 처리할 때 유용해요.
  • 델리게이트 패턴은 객체 전체가 특정 작업을 대신 처리할 수 있게 해주는 패턴이에요. 더 복잡한 작업이나 여러 종류의 작업을 할 때 유용해요.
// 콜백 함수 사용 예시
func fetchData(completion: () -> Void) {
    // 데이터를 가져오는 작업
    print("데이터를 가져오는 중...")
    completion()
}

fetchData {
    print("데이터를 가져왔어요! 이제 사용할 수 있어요.")
}

// 델리게이트 패턴 사용 예시
protocol DataDelegate {
    func didFetchData()
}

class DataFetcher {
    var delegate: DataDelegate?

    func fetchData() {
        print("데이터를 가져오는 중...")
        delegate?.didFetchData()
    }
}

class DataManager: DataDelegate {
    func didFetchData() {
        print("데이터를 가져왔어요! 이제 사용할 수 있어요.")
    }
}

let dataFetcher = DataFetcher()
let dataManager = DataManager()

dataFetcher.delegate = dataManager
dataFetcher.fetchData()

 

3. 델리게이트 패턴과 옵저버 패턴의 차이점 및 사용 시기

  • 델리게이트 패턴은 한 객체가 다른 객체에게 특정 작업을 위임하는 경우에 사용돼요. 즉, 델리게이트는 하나의 객체와 하나의 델리게이트가 존재해요.
  • 옵저버 패턴은 여러 객체가 특정 이벤트에 대해 관찰하고 있다가, 그 이벤트가 발생하면 모두에게 알리는 방식이에요. 여러 객체가 동시에 변화나 상태를 관찰할 때 유용해요.

예시:

WeatherStation이라는 객체가 온도 변화를 보고한다고 가정해볼게요.

  • 델리게이트 패턴을 사용하면, 온도 업데이트를 처리하는 하나의 특정 객체만 존재하게 돼요
protocol TemperatureDelegate {
    func didUpdateTemperature(_ temperature: Int)
}

class WeatherStation {
    var delegate: TemperatureDelegate?

    func updateTemperature() {
        let newTemperature = 30
        delegate?.didUpdateTemperature(newTemperature)
    }
}

class Display: TemperatureDelegate {
    func didUpdateTemperature(_ temperature: Int) {
        print("현재 온도는 \(temperature)°C입니다")
    }
}

let station = WeatherStation()
let display = Display()

station.delegate = display
station.updateTemperature()

 

 

  • 옵저버 패턴을 사용하면, 여러 객체가 온도 변화를 관찰하고, 업데이트 시 동시에 알림을 받을 수 있어요
class WeatherStation {
    var observers = [Observer]()

    func addObserver(_ observer: Observer) {
        observers.append(observer)
    }

    func updateTemperature() {
        let newTemperature = 30
        for observer in observers {
            observer.didUpdateTemperature(newTemperature)
        }
    }
}

protocol Observer {
    func didUpdateTemperature(_ temperature: Int)
}

class Display: Observer {
    func didUpdateTemperature(_ temperature: Int) {
        print("Display: 현재 온도는 \(temperature)°C입니다")
    }
}

class Logger: Observer {
    func didUpdateTemperature(_ temperature: Int) {
        print("Logger: 온도를 \(temperature)°C로 기록했습니다")
    }
}

let station = WeatherStation()
let display = Display()
let logger = Logger()

station.addObserver(display)
station.addObserver(logger)
station.updateTemperature()

 

이 예시에서는 Display와 Logger 두 객체가 모두 온도 변화를 알림받고, 각각 자신의 방식으로 그 정보를 처리해요.

 

4. 델리게이트 메서드에서 반환값을 사용하는 경우

 때로는 델리게이트 메서드에서 반환값을 사용해, 호출자에게 결과를 돌려줘야 할 때가 있어요. 이 방법을 통해 델리게이트는 단순히 알리는 역할뿐 아니라, 호출자에게 결과나 데이터를 돌려줄 수 있어요.

예시:

예를 들어, Restaurant 클래스가 있고, 이 클래스가 Customer에게 무얼 주문할지 물어보는 상황을 생각해볼게요

protocol RestaurantDelegate {
    func orderFood() -> String
}

class Restaurant {
    var delegate: RestaurantDelegate?

    func takeOrder() {
        if let order = delegate?.orderFood() {
            print("주문이 접수되었습니다: \(order)")
        } else {
            print("주문이 접수되지 않았습니다.")
        }
    }
}

class Customer: RestaurantDelegate {
    func orderFood() -> String {
        return "파스타"
    }
}

let restaurant = Restaurant()
let customer = Customer()

restaurant.delegate = customer
restaurant.takeOrder()

 

 

이 예시에서, Customer는 어떤 음식을 주문할지 Restaurant에게 알려주고, 식당은 그 주문을 처리해요.

정리

  • 델리게이트 패턴: 객체의 책임을 다른 객체에게 위임하고, 주로 하나의 객체가 델리게이트로 설정돼요.
  • 콜백 함수: 특정 작업이 끝났을 때 호출되는 함수로, 단순한 작업에 적합해요.
  • 옵저버 패턴: 여러 객체가 이벤트를 관찰하고, 모두에게 알리는 방식이에요.
  • 반환값을 사용하는 델리게이트 메서드: 호출자에게 결과나 데이터를 돌려줄 때 유용해요.