About Delegate Pattern
[오늘은 처음으로 3번 이상 강의를 수강하게 한 ‘델리게이트 패턴’에 대해서 정리하고자 한다.]
- 보통 앱 View를 구상할 때, 한 화면 내에서 모든 거를 처리한다기 보단, 다른 화면과의 상호 작용을 기반으로 한 화면의 데이터를 수정하거나 여러 화면 간의 통신을 설정하는 것은 일반적이다.
그렇다면 디자인 패턴 중 하나인 ‘Delegate Pattern’은 뭘까?
Delegate?
- delegate을 해석하자면 “대리자” 라는 뜻이다.
- 이는 entity가 다른 entity에게 task나 책임을 할당할 필요가 있을 때 사용된다.
- entity? → https://modelinspring.tistory.com/90 해당 블로그 글을 참고하자.
예시를 보면서 한번 알아보도록 하자.
→ 우선적으로 기억해야될 부분은 “객체와 객체 간 의사소통을 하기 위해 대리자(프로토콜 타입) 설정 하는 것” 이다.
예전에 좋아했던 게임 중에 “HitMan”이라는 게임이 있었는데, 암살자의 역할에 대한 내용으로 서술해보자.
우선적으로 암살자는 hit 그리고 run을 해야만 한다. 암살자의 자격증(protocol로 비유)은 사람을 hit, run해야 하는 것이다.
protocol HitAndRunControlDelegate {
func hit()
func run()
}
암살자의 수장은 암살자들에게 hit, run할 것을 위임해야(delegate) 한다.
- 임무를 받은 암살자들은 의뢰를 수행하고, 각자 맡은 임무를 진행해야 한다.
- 아래 HitManControl은 암살자의 수장같은 역할이다.
- 각 delegate 변수에 HitAndRunControlDelegate 프로토콜을 채택하는 각 암살자(객체)를 배정하고, 조종해야 한다.
class HitManControl {
weak var delegate: HitAndRunControlDelegate?
func hit() {
delegate?.hit()
}
func run() {
delegate?.run()
}
}
그렇다면 임무를 받은 각 암살자들은 어떻게 해야되는가?
- 각자 맡은 임무(클래스) 별로 다른 일을 수행해야 한다.
- 단, HitAndRunControlDelegate를 채택한… 즉 암살 자격증인 hit, run을 수행해야 하는 자들이므로 각자 사정에 맞도록 구현을 해줘야 한다.
class DiabloPlayer: HitAndRunControlDelegate {
init(player: HitManControl) {
player.delegate = self // remote.delegate = DiabloPlayer
}
func hit() {
print("Kill Diablo")
}
func run() {
print("Run from Diablo")
}
}
class HitManPlayer: HitAndRunControlDelegate {
func hit() {
print("Kill Boss")
}
fun run() {
print("Run from Boss")
}
}
아래는 각 암살자들의 수행과 같다.
var remote = HitManControl()
let tarzan = DiabloPlayer()
remote.delegate = tarzan
remote.hit() // Kill Diablo
remote.run() // Run from Diablo
let zeus = HitManPlayer()
remote.delegate = zeus
remote.hit() // Kill Diablo
remote.run() // Run from Diablo
//Kill Diablo
//Run from Diablo
//Kill Boss
//Run from Boss
이와 같이 범용성의 확대를 위해 우리가 제작한 프로토콜을 쓰는 경우도 있지만
- UI요소에서의 Delegate Pattern도 한 번 참고해보자
[아래 블로그 글을 참고하였습니다.]
[iOS] Delegate 패턴을 이해해보자
Delegate v.(권한업무 등을) 위임하다
velog.io
우리는 애플에서 만든 UITableView의 내부 코드를 수정할 수 없다.
즉, 애플이 숨겨놓은 테이블뷰 안의 코드를 수정할 수 없다는 거다.
따라서 다른 객체에서 해당 코드를 작성해준 뒤, 테이블뷰가 해당 객체의 코드를 호출해줘야 한다.
→ 이 때 객체 간의 의사소통을 하기위한 방식이 ‘Delegate Pattern’이다.
// Delegate Protocol
protocol UITableViewDelegate: AnyObject {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
}
// Delegating Object
class UITableView {
weak var deleaget: UITableViewDelegate?
func didSelectedRowAt(indexPath: IndexPath) {
delegate?.tableView(self, didSelectRowAt: indexPath)
}
}
// Delegate Object
class ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
print(indexPath)
}
}
- 이벤트를 받는 객체가 해당 이벤트로 어떤 행동을 할지를 delegate에게 위임.
- delegate → 어떤 객체가 이벤트를 만났을 떄 그 객체를 대신해서 행동하는 객체
- delegating 객체는 이벤트를 받고 처리하는 responder 객체.
강의 코드
import UIKit
// UITextFieldDelegate 프로토콜을 상속
class ViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var textField: UITextField!
// textField의 대리자가 뷰컨트롤러가 된다.
// -> textField에서 일어나는 일을 전달받아, 실행하고픈 내용들을 실행시킨다.
override func viewDidLoad() {
super.viewDidLoad()
...
textField.delegate = self
}
...
func textFieldDidBeginEditing(_ textField: UITextField) {
print(#function)
}
}
나의 정리
- UITextFieldDelegate: 반드시 채택할 내용을 가지는 프로토콜
- ViewController: 대리자
- UI → 대리자를 통해 일을 시키며 영향을 받는 존재.
참고
반응형
'iOS > Swift' 카테고리의 다른 글
About Clousre (Basics) (0) | 2024.03.19 |
---|---|
About Class, Struct (1) | 2024.03.19 |
[Swift] Date, Calendar, DateFormatter (1) | 2024.02.25 |
Result Type에 대한 이해 (1) | 2024.02.19 |
제네릭(Generics) (0) | 2024.02.18 |