본문 바로가기
아키텍처+디자인패턴

Delegate 패턴

by 나리._. 2022. 2. 9.

Delegate 패턴은 ios 개발을 하면서 정말 많이 사용한다.

애플이 만들어놓은 것을 쓰며 편하게 개발을 해왔지만 정작 delegate 패턴이 무엇인지 정확하게 알지 못했..!

 

그래서 이번 포스팅은 Delegate 패턴에 대해 정리해볼 것이다.

먼저, 애플 developer 사이트에 뭐라고 설명되어있는지 확인해보잣!

 

앱 관련 메시지에 응답하기 위한 앱 위임 개체가 있어야 하고

앱 실행이 완료되고 포그라운드 또는 백그라운드 실행 상태가 변경될 때 대리자에게 알린다고 적혀있다.

 

이게 무슨 말일까?

 

protocol RemoteControlDelegate {
    func channelUp()
    func channelDown()
}

class RemoteControl {
    
    var delegate: RemoteControlDelegate?

    func doSomething() {
        print("리모콘의 조작이 일어나고 있음")
    }
    
    func channelUp() {   // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨
        delegate?.channelUp()
    }
    
    func channelDown() {   // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨
        delegate?.channelDown()
    }
}

여기서 RemoteControlDelegate 프로토콜은 우리가 자주 쓰던 애플이 제공하는 Delegate들 같은 존재이고 (ex: UITextFieldDelegate, UITableViewDelegate 등등 같은 존재..)

RemoteControl은 직접적으로 유저와 커뮤니케이션하는 객체이다. (ex: TextField, UITableView 등등)

 

Delegate 패턴은 delegate (위임하다) 라는 뜻 그대로

대리자를 갖고 있는 객체가 다른 객체에게 자신의 일을 위임(대리)하는 디자인 패턴이다.

 

위의 코드에서 

var delegate: RemoteControlDelegate? 로 선언했기 때문에

RemoteControlDelegate을 채택한 타입이면 대리자 가능!

 

 

여기서 왜 직접 구현하지 않고 굳이 이렇게 Delegate 패턴을 쓰게 만들었을까?

 

애플은 개발자가 어떤 이름으로 구현할지 알지 못하기 때문에 이름과 상관없이 프로토콜을 채택한 타입은 다 가능하게!

해주기 위해 delegate를 통해서 대리자를 지정할 수 있고 그 대리자에게 이벤트를 알려줄 수 있고 구현하게 할 수 있는 것이다..

 

또 애플이 만든 delegate가 아니더라도 우리는 이 패턴을 통해 코드의 재사용성을 높일 수 있다!

동일한 작업을 수행하는 코드를 여러 개의 객체에서 다른 내용으로 처리해야 하는 경우를 생각해보면

각 객체마다 여러 번 구현하는 것보다 공통된 부분을 한번 구현한 후 (delegate)

각 객체에서 이것을 재사용을 하고 그 외의 부분만 처리하게 된다면

무의미하게 반복되어 가독성을 떨어트리고 유지보수를 어렵게 하는 코드를 없앨 수 있다.

 

그래서 우린 Delegate들을 채택해서 사용한다.

 

Delegate 패턴 예시

// TV 클래스
class TV: RemoteControlDelegate {
    
    func channelUp() {
        print("TV의 채널이 올라간다.")
    }

    func channelDown() {
        print("TV의 채널이 내려간다.")
    }

}

let remote = RemoteControl()
let samsungTV = TV()

remote.delegate = samsungTV 
// 우리는 보통 뷰컨트롤러 객체내에서 쓰기 때문에 remote.delegate = self 이렇게 쓰는 것.


remote.channelUp()        // 리모콘 실행 ====> delegate?.channelUp()
remote.channelDown()      // 리모콘 실행 ====> delegate?.channelDown()


// SmartPhone 클래스
class SmartPhone: RemoteControlDelegate {

    init(remote: RemoteControl) {
        remote.delegate = self       // remote.delegate = smartPhone
    }
    
    func channelUp() {
        print("스마트폰의 채널이 올라간다.")
    }
    
    func channelDown() {
        print("스마트폰의 채널이 내려간다.")
    }
}

(또 다른 뷰컨트롤러의 역할 - 리모콘과 커뮤니케이션)

let smartPhone = SmartPhone(remote: remote)
remote.channelUp()        // 리모콘 실행 ====> delegate?.channelUp()
remote.channelDown()      // 리모콘 실행 ====> delegate?.channelDown()

 

정리하자면

우리는 TextField, TableView, CollectionView 등등 

애플이 만든 수많은 프레임워크의 내부 구현은 알 수 없기 때문에

 

유저와 커뮤니케이션을 할 때 (ex TextField: 유저가 입력을 시작할 때, 한글자씩 입력되는 순간..등) 

동작을 delegate 설정한 객체(애플이 만든 프로토콜을 채택해야함)를 통해 전달을 하는 것이다. !!!

 

이렇게 Delegate 패턴을 통해 애플이 만든 프레임워크의 내부 구현을 알지 못해도

우리는 자알~ 쓰고 있는 것이다..