Search
Duplicate

Delegate(델리게이트) 패턴

생성일
2023/06/29 09:13
태그
Pattern

델리게이트 패턴

델리게이트 : 대리자 라는 뜻
iOS 개발의 핵심/필수 패턴

Responder의 이해 (응답자 / 응답 객체)

UIWindow (앱의 화면)

실제 터치 등, 화면의 입력을 받아들이는 객체
First 응답 객체를 지정 해준다 (화면에서 일단 먼저 반응할 녀석!)
텍스트 필드가 First 응답 객체가 되면 → 키보드가 올라온다.
한마디로 유저한테 먼저 반응할 것을 포커스를 시켜준다.
// First응답객체를 textfield로 설정 만들어준다! -> 실행되자마자 키보드가 올라온다! textField.becomeFirstResponder()
Swift
복사
그러면 키보드를 내리려면?
// 키보드 내리게 한다. textField.resignFirstResponder() // 여백 눌렀을 때 키보드 내리게 // 화면의 탭을 감지하는 메서드 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.view.endEditing(true) // text.resignFirstResponder() }
Swift
복사
텍스트필드는 뷰컨트롤러와 다른 객체이다. 텍스트필드는 유저와 커뮤니케이션을 하기 때문(입력, 터치)
텍스트필드에서 뷰컨트롤러에 동작을 전달하기 위해서 델리게이트(대리자) 패턴이 필요하다!
텍스트필드의 대지라는 뷰컨트롤러
직접적인 동작은 텍스트필드가, 동작 후의 결과를 뷰컨트롤러에 전달, 뷰컨트롤러는 대리자의 역할을 하면서 동작들을 하게 할건지, 아닌지 대리자로서 판단!
// // ViewController.swift // TextFieldProject // // Created by KIM Hyung Jun on 2023/06/30. // import UIKit class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.delegate = self // 내부의 대리자를 self(viewController)로 설정 setup() } func setup() { view.backgroundColor = UIColor.gray textField.keyboardType = UIKeyboardType.emailAddress textField.placeholder = "이메일 입력" textField.borderStyle = .roundedRect textField.clearButtonMode = .always textField.returnKeyType = .go // First응답객체를 textfield로 설정 만들어준다! -> 실행되자마자 키보드가 올라온다! textField.becomeFirstResponder() } // 여백 눌렀을 때 키보드 내리게 // 화면의 탭을 감지하는 메서드 override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.view.endEditing(true) // text.resignFirstResponder() } // textfield의 입력을 시작할 때 호출 (editing을 시작하는 걸 허락할지 말지) func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { print(#function) return true } // 시점 - 텍스트필드를 쓰려고 터치한 순간 func textFieldDidBeginEditing(_ textField: UITextField) { print(#function) print("유저가 텍스트필드의 입력을 시작했다.") } // 깔끔하게 없애는 걸 허락할지 말지 func textFieldShouldClear(_ textField: UITextField) -> Bool { print(#function) return true } // 한글자 한글자 입력할 떄마다 호출! --> 참(입력하는 것을 허락) / 거짓(입력하는 것을 거부) // 텍스트필드 글자 내용이 (한글자 판글자) 입력되거나 지워질 때 호출이 되고 (허락) func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { // print(#function) // print(string) // let maxLength = 10 // let currnetString: NSString = (textField.text ?? "") as NSString // let newString: NSString = // currnetString.replacingCharacters(in: range, with: string) as NSString // return newString.length <= maxLength if Int(string) != nil { return false } else { guard let text = textField.text else { return true } let newLength = text.count + string.count - range.length return newLength <= 10 } } // 텍스트필드의 엔터키가 눌러지면 다음 동작을 허락할건지 말건지 func textFieldShouldReturn(_ textField: UITextField) -> Bool { print(#function) if textField.text == "" { textField.placeholder = "Type Something!" return false } else { return true } } // 텍스트필드의 입력이 끝날때 호출 (끝날지 말지를 허락) func textFieldShouldEndEditing(_ textField: UITextField) -> Bool { print(#function) return true } // 텍스트필드의 입력이 실제 끝났을 때 호출 (시점) func textFieldDidEndEditing(_ textField: UITextField) { print(#function) print("유저가 텍스트필드의 입력을 끝냈다.") textField.text = "" } @IBAction func doneButtonTapped(_ sender: UIButton) { // 키보드 내리게 한다. textField.resignFirstResponder() } }
Swift
복사

델리게이트 패턴의 구조

텍스트필드와 뷰컨트롤러 간의 의사소통(대리자 설정)을 하기 위해서 프로토콜을 사용한다.
델리게이트 패턴의 핵심은 객체와 객체 간의 커뮤니케이션을 돕는 것!
뷰컨트롤러에게 상황에 대한 판단(동작)을 위임 가능
객체간 쌍방향 커뮤니케이션 가능 (데이터를 주고 받는 것도 가능)
ex. 리턴값에 따라 텍스트 필드는 동작할지 말지 판단
프로토콜을 사용함으로써 텍스트필드의 내부 구현을 숨길 수 있음
import UIKit // 자격증(정의) (텍스트필드 프로토콜) protocol RemoteControlDelegate { func channelUp() func channelDown() } // 리모콘 클래스(텍스트필드의 역할 - 직접적으로 유저와 커뮤니케이션) class RemoteControl { var delegate: RemoteControlDelegate? func doSomething() { print("리모콘의 조작이 일어나고 있음") } func channelUp() { // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨 delegate?.channelUp() } func channelDown() { // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨 delegate?.channelDown() } } // TV 클래스(뷰컨트롤러의 역할 - 리모콘과 커뮤니케이션) class TV: RemoteControlDelegate { func channelUp() { print("TV의 채널이 올라간다.") } func channelDown() { print("TV의 채널이 내려간다.") } } let remote = RemoteControl() let samsungTV = TV() remote.delegate = samsungTV remote.channelUp() // 리모콘 실행 ====> delegate?.channelUp() remote.channelDown() // 리모콘 실행 ====> delegate?.channelDown() // SmartPhone 클래스(뷰컨트롤러의 역할 - 리모콘과 커뮤니케이션) class SmartPhone: RemoteControlDelegate { init(remote: RemoteControl) { remote.delegate = self // remote.delegate = smartPhone } func channelUp() { print("스마트폰의 채널이 올라간다.") } func channelDown() { print("스마트폰의 채널이 내려간다.") } } let smartPhone = SmartPhone(remote: remote) remote.channelUp() // 리모콘 실행 ====> delegate?.channelUp() remote.channelDown() // 리모콘 실행 ====> delegate?.channelDown()
Swift
복사

텍스트필드는 왜 델리게이트 패턴이 필요할까? (왜 레이블과 사용법이 다를까?)

텍스트필드는 동작이 복잡하다. 그런 복잡한 동작을 제대로 하나하나 구현하려면, 동작이 일어나는 행동은 텍스트필드에서 일어나고, 결과를 뷰컨트롤러한테 전달하면서 시점을 파악한다든지, 뷰컨트롤러에게 물어보는 것이다.
→ 훨씬 더 복잡한 동작을 구현하기 위해서 델리게이트 패턴이 필요하다(프로토콜을 사용하면서)

델리게이트 메서드를 왜 다 미리 구현해놨을까?

개발자의 편리를 위해서!