-
UIKit에서 Delegate Pattern를 쓰는 이유공부/iOS 2023. 12. 21. 14:38
# 시작하기 전...
UIKit을 처음 접했을 때 가장 당황했던 것은 호출하지 않고도 실행되는 함수였습니다.
무슨 소리인가? 싶겠지만 정말 func 로 구현은 되어있는데 어디에도 호출은 하지 않았지만 분명 그 코드는 동작하고 있었던 것이죠.
그 미스테리의 정체는 오늘 알아볼 Delegate입니다.
# Delegate란?
Delegate를 직역하면 위임자란 뜻입니다.
(이걸 처음 봤을 때 나의 심정)
도대체 무슨 소리인가 싶고, 설명도 잘 이해가 되지 않죠...
뭔가 위임자라고 하면 뭔가 대신 일을 처리해주는 종속된 관계가 아닐까 생각했다.하지만 정 반대로 일종의 Delegate를 채택하는 쪽이 팀장님, 요청하는 쪽이 직원에 가깝습니다.
Delegate를 생성하는 과정을 비유를 섞어 설명해볼게요.
1. Delegate 생성 및 채택
회사에는 작업이 완료될 때 마다 보고를 하는 프로세스가 있습니다.
구체적인 내용은 각 팀장의 재량에 맡깁니다.
protocol WorkerDelegate: AnyObject { // 작업 종료 후에 보고하기 func didFinishWork() }
2. WorkerDelegate 프로토콜 채택
한 팀장님이 이 체계가 마음에 들어 자신의 팀에도 도입하기로 합니다.
보고를 할 때는 PPT를 만들어야 한다는 것을 추가합니다.
extension ManagerViewController: WorkerDelegate { func didFinishWork() { // 작업이 완료된 후에 업무를 보고합니다. // PPT를 만든 뒤에 발표하세요. print("업무 보고") } }
3. WorkerDelegate를 선언
위에서 시키면 시키는대로 할 준비가 된 성실한 직원입니다.
class Worker { weak var delegate: WorkerDelegate? }
4. ManagerViewController가 worker의 대행자
위 직원을 팀장님(ManagerViewController)이 "직접" 직원(Worker)을 담당하기로 합니다.
class ManagerViewController: UIViewController { private let worker = Worker() override func viewDidLoad() { super.viewDidLoad() // self = ManagerViewController worker.delegate = self } }
5. Worker에서 작업 구현
Worker의 일을 정의합니다. 여기에는 업무가 끝난 뒤에 보고하는게 포함되어있습니다.
여기서 didFinishWork()는 팀장님이 시켰던 PPT를 포함한 업무보고입니다.
class Worker { weak var delegate: WorkerDelegate? func doWork() { // 업무를 수행합니다. // // 업무 수행이 끝난 뒤에 일이 다 끝났다고 관리자에게 보고를 합니다. delegate?.didFinishWork() } }
6. 구현한 작업을 실행
worker에게 작업을 시킵니다.
위에서 구현한대로 worker는 업무의 마지막 단계에서 2번에서 구현한 함수를 실행하면서 보고를 할 것입니다.
class ManagerViewController: UIViewController { private let worker = Worker() override func viewDidLoad() { super.viewDidLoad() worker.delegate = self // 직원에게 일을 시킵니다. worker.doWork() } }
# 이해하기
이 모든 과정은 팀장님과 직원의 1:1 커뮤니케이션으로 진행됩니다.
만약 팀장님이 바뀌어 보고체계에 변화가 생긴다면?
Worker의 코드는 바꿀 필요가 없습니다. 그저 하던 작업을 똑같이 수행하면 됩니다!
Delegate를 채택한 팀장(NewViewConroller)에서 didFinishWork의 구현부만 수정하면 된다는 뜻이니까요 ㅎㅎ
만약 보고를 할 담당자가 아무도 없다면? (worker.delegate = nil)
그럼 업무만 딱 수행하고 별도의 보고는 안해도 되겠죠!
# 활용하기
이런 특이한 구조가 실전에서 어떻게 활용할 수 있을까요?
UITextFieldDelegate를 예시로 들어서 설명해볼게요.
평소 텍스트필드만 사용할 때는 이용할 수 없던 메서드를 Delegate를 채택하면 사용할 수 있게 됩니다.
그럼 shouldChangeCharactersIn을 활용해 텍스트의 최대 길이를 10으로 제한해보겠습니다!
extension ViewController: UITextFieldDelegate { func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let length = textField.text!.count + string.count - range.length textField.layer.borderWidth = 3.0 textField.layer.borderColor = length <= 10 ? UIColor.green.cgColor : UIColor.red.cgColor return length <= 10 } }
1) textField.text!.count: 텍스트필드에 입력되어있는 텍스트의 길이입니다.
2) string.count: 사용자가 입력에 새롭게 추가될 텍스트의 길이 입니다.
3) range.length: 사용자의 입력에 기존 텍스트의 변화하게 될 텍스트의 길이입니다.
이 메서드는 텍스트가 입력될 때 마다 위 함수를 호출해 입력 여부를 결정하게 됩니다.
만약 사용자가 10글자를 초과한 입력을 하게 된다면 입력이 불가능하겠죠.
ViewController에서 최대 길이에 대한 제한을 걸 수도 있겠지만, 이렇게 간단하게 함수를 구현만 하더라도 제약을 걸 수 있는 것이죠.
또한 이 함수가 사용자가 입력할 때 마다 호출된다는 점을 이용해 컬러 변경과 같은 효과를 유동적으로 적용시킬 수도 있겠네요.
# 결론
오늘은 UIKit의 Delegate 패턴에 대해 알아봤습니다.
예제에서 파라미터를 따로 지정해주지 않았지만 UITextFieldDelegate처럼 파라미터를 지정해주면 데이터를 전달하는 역할로도 사용할 수 있게 됩니다. 이를 활용하면 UIViewController와 UIView, UIViewController와 다른 UIViewController 사이에 데이터를 전달하는 용도로 사용할 수 있겠죠.
결국 1:1 관계에선 강력하게 작동한다고 볼 수 있을 것 같습니다.
다만 depth가 길어지거나 공통으로 사용되는 영역이 많은 경우, 통신과 같은 비동기 처리가 잦은 경우에는 부적절해보입니다.
물론 didset 같은거로 막 도배하면 되기는 하겠지만...'공부 > iOS' 카테고리의 다른 글
키체인을 활용해 jwt Token 안전하게 저장하기 (1) 2024.01.16 Xcode15에서 XCTest를 할 때 Testing... 에서 멈추는 현상 (0) 2024.01.02 [UIKit]키보드 위에 수정 제안을 비활성화하기 (0) 2023.12.13 self에서 unexpected 에러가 발생하는 이유 (0) 2023.12.01 [Swift] Date formatted, FormatStyle로 날짜 출력하기 (0) 2023.07.19