Delegate Pattern🤔
안녕하세요 Ruel입니다
오늘은 Delegate Pattern에 대해 간단하게 알아보려해요.
저는 Delegate Pattern이 익숙하게 주로 사용하고 있었는데,
맨 처음 마주했을때는 흐름을 이해하지 못해서 어질어질하더라구요🌀
자주 사용되는 만큼 간단하게라도 정리해보려해요
Delegate Pattern이란?
- 사전에 따르면 Delegate는 ‘위임하다’라는 뜻을 가지고 있어요
Delegate Pattern은 하나의 객체가 다른 객체에게 특정 작업이나 이벤트를 처리하도록 위임하는 디자인 패턴이에요
Delegate Pattern을 사용하면 객체간 결합도를 낮추고, 유연하고 재사용 가능한 코드를 작성할 수 있어요
사실 글로만봤을때 결합도를 낮추고, 유연하고 재사용가능하다? 라는말을 이해하기 힘들 수 도 있는데
iOS 개발 시 자주 볼 수 있는 코드를 가지고 살펴볼게요.
Swift에서 Delegate 사용 예시
Swift에서는 다양한한 곳에서 Delegate Pattern을 사용하고 있어요
대표적으로는 UITableView, UICollectionView, UITextField등이 있어요
TableView를 예를 들어볼게요
UITableView는 리스트 형태의 데이터를 표현하는데 사용되는데 데이터 소스 및 상호작용을 위해 두가지 Delegate 프로토콜을 사용해요
UITableViewDataSource & UITableViewDelegate
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self // ViewController에게 delegate를 위임함
tableView.dataSource = self // ViewController에게 dataSource를 위임함
}
// UITableViewDataSource 메서드
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 10
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "Row \\(indexPath.row)"
return cell
}
// UITableViewDelegate 메서드
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print("Selected row at \\(indexPath.row)")
}
}
- 위 코드처럼 UITableView를 정상적으로 동작시키기 위해서는 ‘UITableViewDelegate’ , ‘UITableViewDataSource’를 채택 해야하는데요.
채택을 하게 된다면 ‘UITableViewDataSource’는 필수로 구현해야하는 메서드들이 있습니다.
(⭐️ 필수가 아닌 메서드들도 있어요. 목적에 맞게 필요한 메서드를 사용하면돼요! )
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
리스트를 구성하기위해 몇개의 Cell이 필요한지, Cell은 어떻게 그려질 것인지에 대한 메서드들을 구현해야하는데
여기서 Delegate를 이해하자면
‘UITableViewDataSource’ 는 이렇게 말할거에요
“이거 필수로 해야해 근데 내가 안할거고 너가해”
즉, TableView의 동작은 Delegate를 통해 ViewController에서 명령을 전달하고
해당 명령에 대한 내용을 ViewController에서 작업을 한다!
라고 볼 수 있겠네요
Custom Delegate
조금 더 이해해보기 위해서 직접 Delegate를 만들어볼게요
엄마(Delegate)는 아이(Object)에게 숙제를 시키고, 아이가 숙제를 다하면 엄마에게 알려주는 그런 Delegate Pattern을 만들어 볼게요
1. Delegate Protocol 생성
- Delegate Pattern의 핵심은 Protocol이에요. Protocol은 특정 이벤트나 작업에 대한 메서드를 정의하는 인터페이스에요.
protocol HomeworkDelegate: AnyObject {
func didFinishHomework()
}
- 이 Protocol에 정의된 메서드는 아이가 숙제를 다했을때의 말을 정해놓은거에요
2. Delegating Object
- 아이 역할을 하는 객체에요. 숙제를 다했다고 엄마에게 알려주는 역할을 해요
class Student {
weak var delegate: HomeworkDelegate?
func finishHomework() {
delegate?.didFinishHomework()
}
}
3. Delegate Object
- 엄마의 역할을 객체에요. 숙제를 다했다라고 알려주면 이를 확인하게 돼요
class Mother: HomeworkDelegate {
func didFinishHomework() {
print("Well done! Now you can play.")
}
}
살펴보자면 Protocol로 특정 행동에 관한 메서드를 정의 해놓았어요
이 protocol의 메서드를 실행시켜야하는 곳(Student)에서
weak var delegate: HomeworkDelegate?
와 같이 선언해주면 해당 Protocol의 메서드를 호출할 수 있죠!
그렇다면 해당 Protocol을 채택하고 있는 곳(Mother)에서는 필수적으로 Protocol의 메서드를 구현해야하는데요
이때, 메서드 내부 코드도 구현을 해주게 돼요
자 이제 아이가 숙제를 다했다고 외쳐요 (finishHomework())
그럼 delegate의 didFinishHomework()를 호출하게 되죠
해당 Protocol을 채택하고 있는 Mother 객체에서 didFinishHomework() 가 실행 되면서
내부에 구현한 print가 출력되게 되죠!!!!!
이해가 되셨나요???
간단한 예제이기 때문에 이해가 되셨을꺼라고 생각해요!
이렇게 Delegate Pattern을 사용하면 어떤 장점, 단점이 있을까요?
Delegate Pattern 장점
- 객체 간 결합도를 낮춰 각각 독립적으로 동작 할 수 있어요
- 델리게이트 객체를 교체함으로 동작을 변경할 수 있어요
- 델리게이트 패턴을 사용하면 코드의 재사용성이 높아져요
Delegate Pattern 단점
- 객체 간 관계가 많아지면 많아질수록 코드의 복잡도가 증가해요
- 강한 참조 순환을 피하기 위해 델리게이트는 주로 weak(약한 참조)로 선언해야해요. 그렇지 않으면 메모리가 해제되지 않는 상황이 발생할 수 있어요
이렇게 간단하게 Delegate Pattern에 대해 알아보았는데,
항상 익숙하게 사용하고 있었지만 막상 설명을 하려니 쉽지 않네요...
잘못된 부분 혹은 새롭게 알려주실 부분 있으시면 언제든지 댓글 남겨주세요.💬
감사합니다.🙇🏻♂️