오늘은 Delegate Pattern
에 대해 알아보자.
Delegate Pattern
은 iOS 개발하다보면 정말 많이 보게된다.
나는 TableView를 사용하면서 처음 봤었다.
그때는 protocol
에 대한 이해도 없었고, 타이트한 일정으로 제대로 알아볼 생각을 못했었다.
그냥 TableView를 사용할때 DataSource
와 Delegate
를 사용할 수 있구나.
cell을 클릭해서 이동하고 싶을때 Delegate
를 사용할 수 있구나 싶었다.
Delegate
는 iOS를 개발할때에 많이 만나고 그만큼 완벽한 이해가 필요하다 생각한다.
Delegate
혹은 Delegation
을 검색하다보면
Delegation
은 일부 클래스의 책임을 다른 클래스의 인스턴스에게 위임 또는 전달할 수 있는 디자인 패턴
위와 같은 문구를 자주 접하게 된다.
쉽게 말하면 Delegation
은 내가 해야 할일을 다른 인스턴스로 넘겨버린다고 할 수 있다.
UITableView
를 생각해보면, table cell을 클릭했을때 동작을 UITableView
가 처리해야하지만 UITableViewDelegate
로 떠넘겨 버린다.UITextView
를 생각해보면, textView의 수정이 끝났는지 확인을 UITextView
가 처리해야하지만 UITextViewDelegate
로 떠넘겨 버린다.Delegation
을 이해하는데 아래 내용을 생각하면서 봐보자.
그럼 우리는 익숙한 UITableView
로 이해를 해보자.
UITableVeiw
에서 table cell을 클릭하여 다른 화면으로 이동하고 싶다면 어떻게 코드를 작성할까?
class ViewController: UIViewController {
@IBOutlet weak var table: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
table.delegate = self
}
}
extension ViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let secondViewController = UISecondViewController()
self.navigationController?.pushViewController(secondViewController, animated: true)
}
}
위의 코드는 익숙할거다.
그래도 하나씩 뜯어보자.
TableView
를IBOutlet
으로 지정해줬다.table.delegate = self
로 TableView
의 delegate
를 지정해줬다.ViewController
는 UITableViewDelegate
를 채택하고, didSelectRowAt
메서드에서 해당 작업을 작성해줬다.결과적으로 ViewController
의 table
은 cell 클릭시 해야할 일을 UITableViewDelegate
에 떠넘기게 되었다.
본격적으로 내용을 살펴보기 전에
ViewController
는UITableViewDelegate
를 채택
라고 했는데 채택!! 채택!! 뭔가 생각나지 않나?!
이전 프로토콜 포스팅에서 프로토콜은 채택한다고 했다.
그렇다면 Delegate
는 Protocol
로 구성되어 있을까?!
❗️맞다!!
이 부분은 잠시 후 다시 다룰 것이니 지금은 "Delegate
는 Protocol
로 구성되어 있으므로 채택한다고 해야하는구나"까지만 알아두자.
우리는 먼저 TableViewDelegate
를 사용하는 과정과 맨 위에서 알아두라고 했던 내용과 짝지어 볼것이다.
table.delegate = self
로TableView
의delegate
를 지정해줬다.ViewController
는UITableViewDelegate
를 채택하고,didSelectRowAt
메서드에서 해당 작업을 작성해줬다.
- 수신자 Receiver
- 대리자 Delegate
- 대리자에게 수신자 자신을 전달
위의 코드에서 대리자는 누구일까?
❗️ UITableViewDelegate
이다.
tableView
로부터 cell 클릭시 해야할 일을 위임 받았기 때문이다.
위의 코드에서 수신자는 누구일까?
❗️ ViewController
의 table
프로퍼티이다.
UITableViewDelegate
의 결과를 table
이 받기 때문이다.
table.delegate = self
를 통해 대리자에게 수신자 자신을 전달하고 있다.
우리는 위에서 UITableViewDelegate
를 통해 Delegation
을 알아봤다.
그럼 Delegation
은 Apple이 미리 만들어 놓은 것만 사용할 수 있는걸까?!
오늘 포스팅 제목을 생각해보면 힌트를 얻을 수 있다.
우리는 Delegate Pattern을 알아보기로 했다.
위에서는 Delegation
이 어떤 것이고, 어떻게 설정?사용?하는지 알아봤고 이해를 위해 가장 많이 접해봤을 예시를 가져온 것 뿐이다.
Pattern은 말 그대로 패턴일뿐여서 iOS에서 자주 쓰이지만 다른 언어에도 적용할 수 있다.
사실 내가 처음 Delegate
를 접했을때 어려웠던 이유는 패턴이라고 생각하지 못했고, 그래서 Apple이 미리 만들어 놓은 것만 사용할 수 있다 생각했었기 때문이다.
그리고 Delegate Pattern은 Protocol
을 사용하게되는데 그당시 Protocol
에 대한 이해가 없었다.
또한, 수신자/대리자/대리자에게 수신자 자신을 전달을 이해하지 못했다.
(근데... 많이 사용해서 감으로 이해하게 되었다...)
그럼 우리는 수신자/대리자/대리자에게 수신자 자신을 전달을 생각하면서 Delegate Pattern
을 만들어보자.
왼쪽이 첫번째 화면이고, 버튼을 누르면 오른쪽 화면으로 넘어간다.
오른쪽 화면에서 버튼을 누르면 첫번째 화면의 label의 텍스트가 바뀌도록 구현하고 싶다.
흠...
두번째 화면에서 버튼을 누르는데 첫번째 화면의 텍스트가 바껴...?
❗️그럼 첫번째 화면의 텍스트 바꾸는 부분을 다른 애한테 위임해야겠네..?!
class ViewController: UIViewController {
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
}
@IBAction func touchUpButton(_ sender: Any) {
guard let secondViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(identifier: "second") as? SecondViewController else {
return
}
secondViewController.secondButtonDelegate = self
self.present(secondViewController, animated: true, completion: nil)
}
}
extension ViewController: SecondeButtonDelegate {
func changeButton() {
self.label.text = "❗️Delegate를 눌러서 바꼈다!❗️"
}
}
class SecondViewController: UIViewController {
@IBOutlet weak var button: UIButton!
var secondButtonDelegate: SecondeButtonDelegate? = nil
@IBAction func touchUpButton(_ sender: Any) {
self.secondButtonDelegate?.changeButton()
}
}
protocol SecondeButtonDelegate {
func changeButton()
}
SecondController에 Delegate protocol
을 정의했다.
protocol
은 함수의 구현부는 정의하지 않으므로 정의부만 정의했다.
ViewController
에서 버튼을 클릭하면 secondViewController.secondButtonDelegate = self
로 자신을 넘겨주고 있다.
(ViewController
는 수신자 seconViewController.secondButtonDelegate
는 대리자)
SecondController
에서 버튼을 클릭하면 seconButtonDelegate
의 changeButton()
을 실행한다.
대리자는 수신자 객체의 메소드를 대신 실행해주고 있다.
(Label
의 텍스트를 바꿔줌)
원하는대로 잘 동작하는걸 확인할 수 있다.
오늘은 delegate에 대해서 알아봤다.
그럼 이만👋