Delegate 패턴
delegate 패턴은 mvc, mvvm... 처럼 디자인 패턴의 한 종류라고 한다. 하나의 객체가 모든 일을 다 처리하기 보다는 처리할 것 일부를 다른 객체에 넘기는 것이다. 스위프트에서는 delegate 디자인 패턴으로 작성할 때 보통 프로토콜을 많이 활용한다고 한다.
'디자인 패턴'에 대한 정의는 a proven solution to a common problem 인데, 그럼 어떤 problem이 있었길래 delegate 디자인 패턴이 생긴 것일까? 예를 들어, UITextField 라는 클래스가 있다. UITextField를 참조하게 될 많은 클래스들이 텍스트 필드에 어떤 이벤트가 발생하면 UITextField로 부터 알림을 받고 싶을 것이다. 하지만 UITextField가 이 클래스들을 다 아는 것은 불가능하다. 그러면 UITextField를 누가 사용하던지 상관없이 UITextField를 참조하는 곳에 어떻게 알림을 줄 수 있을까? 가 문제였다고 한다. (유데미 강의 참고하였음,,) 그래서 여기에 대한 한 가지 솔루션이 delegate 패턴이라고 한다. delegate로 등록된 클래스가 어떤 것이든 상관없이 UITextField에 어떤 이벤트가 감지 되었을때 delegate로 등록된 클래스의 메소드를 호출하며 알려줄 수 있다. (delegate로 등록된 클래스가 특정 프로토콜을 채택하고 준수하기만 한다면)
UITextField를 사용할 때 아래처럼 UITextField 인스턴스의 delegate 프로퍼티에 해당 클래스를 할당하는데, UITextField 클래스 내부를 보면 실제로 delegate 라는 이름의 프로퍼티가 존재하고 데이터 타입은 UITextFieldDelegate로 되어있다.
import UIKit
class WeatherViewController: UIViewController, UITextFieldDelegate {
@IBOutlet weak var searchTextField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
searchTextField.delegate = self
}
}
그리고 UITextField 클래스 내부에서 찾지는 못했지만 내부 메소드 중에 아마 delegate.UITextFieldDelegate에선언된메소드들중하나() 이런식으로 되어 있는 부분이 있어서 UITextField에서 어떤 이벤트가 발생할 때 delegate된 클래스의 내부에 구현된 delegate 프로토콜의 메소드들을 호출할 수 하는 것 같다.
이렇게 delegate를 이용하면 UITextField는 어떤 클래스가 자기를 참조할 것인지 알 필요도 없고 그저 delegate에 등록된 클래스의 메소드를 필요에 맞게 호출하면 등록된 클래스에서 상황에 맞게 처리하고 싶은대로 처리하면 될 것이다.
프로토콜의 이름: ~Delegate, ~DataSource
프로토콜 이름을 보면 ~Delegate인 것이 있고 ~DataSource인 것이 있는데 이렇게 프로토콜의 이름으로 각각 주로 어떤 목적을 위해 만들어진 것인지 알 수 있다.
- ~Delegate: 주로 어떤 액션에 대한 반응을 하는 메소드의 모음
- ~DataSource: 주로 데이터를 받아 뷰를 그려주는 메소드 모음
delegate 패턴 구현해보기
가짜 UITextField, UITextFieldDelegate, ViewController를 만들어 delegate 패턴 흉내를 내보았다..
1. protocol 만들기 (이름은 ~Delegate면 될 듯)
2. 1에서 만든 protocol을 데이터 타입으로 하는 delegate 프로퍼티를 가지는 클래스 만들기
delegate로 등록하려는 클래스/구조체가 왜 protocol을 채택해야 하냐면, protocol을 채택한 클래스/구조체 내부에 필요한 메소드가 구현되어 있을 것이고 2번 내부에 delegate.프로토콜메소드 처럼 작성되었을 때 delegate로 등록된 클래스/구조체에 구현된 메소드가 호출 될 것이기 때문
3. delegate로 등록하려는 클래스, 구조체에서 init 내부에 자기 자신을 2의 delegate에 할당하기
protocol FakeUITextFieldDelegate {
func keyboardAppeared()
func keyboardDismissed()
}
class FakeUITextField {
var delegate: FakeUITextFieldDelegate?
func startInput() {
delegate?.keyboardAppeared()
}
func endInput() {
delegate?.keyboardDismissed() // delegate로 등록된 클래스/구조체 내부에 구현된 keyboardDismissed 메소드를 호출하게 된다
}
}
class FakeViewController: FakeUITextFieldDelegate {
init(fakeUItf: FakeUITextField) {
fakeUItf.delegate = self
}
func keyboardAppeared() {
print("keyboard appeared!")
}
func keyboardDismissed() {
print("keyboard dismissed!")
}
}
let fakeUITextField = FakeUITextField()
let fakeVC = FakeViewController(fakeUItf: fakeUITextField)
fakeUITextField.startInput() // FakeViewController에서 구현한 print 부분이 출력됨. keyboard appeared!
이건 저번에 정리한 프로토콜. 저번에 이거 포스팅할 때 delegate 패턴도 정리한다고 했었기 때문에...
https://what-whale-wants-to-say-is.tistory.com/94
[swift] 프로토콜 protocol
프로토콜이 좀 생소해서 항상 챙겨보고 있는 아래 유튜브 영상을 많이 참고했다. 아 물론 swift 공식문서도... https://www.youtube.com/watch?v=p19mUgg1CFQ&list=PLJqaIeuL7nuFbWKMhG8-xLzF1T7gIPr8Z&index=69..
what-whale-wants-to-say-is.tistory.com
'swift & iOS > swift' 카테고리의 다른 글
[swift] init 메소드의 종류 (0) | 2022.02.03 |
---|---|
[swift] 프로퍼티 초기화 하는 방법 3가지 (0) | 2022.02.03 |
[swift] 프로토콜 protocol (0) | 2022.01.31 |
[swift] 제네릭 generic <> (0) | 2022.01.28 |
[swift] error handling - throws 메소드 & do ... catch 문 (0) | 2022.01.28 |