본문 바로가기

정보

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

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에게 알려주고, 식당은 그 주문을 처리해요.

정리

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