날짜: 2024년 8월 22일
태그: delegate, iOS

- 이와 같은 텍스트필드가 존재하는 View가 있다.
- 해당 텍스트필드는 해당 뷰컨트롤러(뷰)와는 분리된 또다른 객체이다.
- 유저와 직접적인 커뮤니케이션을 하는 부분으로
- 내부에서 키보드가 동작하며, 키보드는 OS의 관리 영역이다.
- 사용자가 어떠한 동작을 한 뒤에, 동작을 다시 뷰컨트롤러에 전달하는 커뮤니케이션 과정이 일어난다.
- 동작의 형태로는 디테일하게 여러가지가 존재한다.
- etc: 입력 시작, 종료, 변경 .. 등등
- 이와 별개로 버튼의 경우(추천, blue, red…)는 IBAction을 통해 뷰컨트롤러와 직접적인 커뮤니케이션이 가능하다.
즉, 정리해보면
- 텍스트필드는 유저와 커뮤니케이션을 따로 해준 뒤에
- 뷰컨트롤러에 동작을 전달해준다.

- 그러면 어떻게 코드로 할 수 있지?
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var suggestButton: UIButton!
let suggestNickName = ["AAAAA", "BBBB", "CCC", "DD", "E"]
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
setUp()
}
func setUp() {
textField.borderStyle = .line
nextButton.isEnabled = false // 초기 비활성화
teamCharacterImage.image = UIImage(named: "yellow")
}
@IBAction func suggestButtonTapped(_ sender: UIButton) {
if let randomNickname = suggestNickName.randomElement() {
textField.text = randomNickname
validateNickname()
}
}
}
extension ViewController: UITextFieldDelegate {
func textFieldDidChangeSelection(_ textField: UITextField) {
validateNickname()
}
private func validateNickname() {
guard let nickname = textField.text else {
nextButton.isEnabled = false
return
}
let nicknameRegex = "^(?=.*[a-zA-Z])[a-zA-Z0-9]{1,5}$"
let isValid = NSPredicate(format: "SELF MATCHES %@", nicknameRegex).evaluate(with: nickname)
nextButton.isEnabled = isValid
}
}
음… UITextField는 텍스트 필드구나… 하겠지만, UITextFieldDelegate 프로토콜은 뭐지?
UITextFieldDelegate | Apple Developer Documentation
UITextFieldDelegate | Apple Developer Documentation
A set of optional methods to manage editing and validating text in a text field object.
developer.apple.com
UITextField
protocol UITextFieldDelegate 텍스트 필드 객체의 텍스트 편집 및 유효성 검사를 관리하는데 사용하는 선택적인 메소드 집합
medium.com
[우선 공식문서의 설명은 다음과 같다]
A text field calls the methods of its delegate in response to important changes. You use these methods to validate text that was typed by the user, to respond to specific interactions with the keyboard, and to control the overall editing process. Editing begins shortly before the text field becomes the first responder and displays the keyboard (or its assigned input view).
[한글 해석]
textField
는 중요한 변화에 대응하여 델리게이트 메소드를 호출한다. 사용자가 입력한 텍스트를 검증하고, 키보드와의 특정 상호작용에 응답하며, 전체 편집 프로세스를 제어하는데 이 메소드들을 사용한다. 편집은 텍스트 필드가 first responder가 되기 직전 시작되고 키보드(또는 할당된 input view)를 표시한다.
- 난 영어를 잘 못한다…
- 간단히 말하면, 텍스트 필드 객체에서의 텍스트 편집, 유효성 검사를 관리하는데 사용하는 메소드 집합이다.
- First Responder가 뭔가?
- 이벤트를 처음 받는
responder
- 가장 우선순위가 높은
responder
이기도 하다.
- 이벤트를 처음 받는
- 메소드 집합에는 뭐가 있을까?
func textFieldShouldBeginEditing(_ textField: CustomTextField) -> Bool {
// 텍스트 필드에서 편집을 시작할지 말지의 여부를 delegate에게 확인하는 메서
// return false인 경우 편집되지 않음
return true
}
func textFieldDidBeginEditing(_ textField: CustomTextField) {
// 텍스트 필드에서 입력이 시작되었음을 delegate에게 알려주는 메서
// 텍스트 필드 편집 중에 일어나는 메서드
}
func textFieldShouldEndEditing(_ textField: CustomTextField) {
// 텍스트 필드에서 입력을 중지할지 말지의 여부를 delegate에게 확인하는 메서드
}
func textFieldDidEndEditing(_ textField: CustomTextField) {
// 텍스트 필드에서의 입력이 중지되는 시점과 중지된 이유를 delegate에게 알려주는 메서드
}
func textFieldDidEndEditing(_ textField: CustomTextField, reason: CustomTextField.DidEndEditingReason) {
// 텍스트 필드에서 입력이 중지되는 시점을 delegate에게 알려주는 메서드
}
func textField(_ textField: CustomTextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// 텍스트 필드의 입력값이 변경될지의 여부를 delegate에게 묻는 메서드
// textfield에 입력될 때마다 호출되는 함수
// 텍스트 필드 내용이 변경될 때 호출 (입력할 수 있는 텍스트의 길이도 정할 수 있다)
return false
}
func textFieldDidChangeSelection(_ textField: CustomTextField) {
// 텍스트 필드에서 텍스트 선택이 변경되면 delegate에게 알려주는 메서드
}
func textFieldShouldClear(_ textField: CustomTextField) -> Bool {
// 텍스트 필드에 입력된 것들을 지울지의 여부를 delegate에게 묻는 메서드
// 텍스트 필드의 내용이 삭제될 때 호출
return false // false 리턴 시 삭제되지 않음
}
func textField(_ textField: CustomTextField, editMenuForCharactersIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu? {
// 시스템이 제공하는 텍스트 범위 및 action을 기반으로 텍스트 필드에 표시할 메뉴를 delegate에게 요청하는 메서드
return nil
}
@available(iOS 16.0, *)
func textField(_ textField: CustomTextField, willPresentEditMenuWith animator: UIEditMenuInteractionAnimating) {
}
@available(iOS 16.0, *)
func textField(_ textField: CustomTextField, willDismissEditMenuWith animator: UIEditMenuInteractionAnimating) {
}
뭐 대충 어떤 느낌인지… 뭐가 있는 지도 알겠다.
그런데 Delegate라는 게 여전히 감이 안 잡힌다…
[우선 단어의 의미부터 보자]
Delegate?
- 대리자, 대표
[그럼 델리게이트 패턴은 뭐지?]
Delegate Pattern?
[객체와 객체간의 커뮤니케이션을 위한 패턴]
[커뮤니케이션은 프로토콜을 통해 진행된다.]
즉..!
- Delegate 패턴은 하나의 객체가 다른 객체에 특정 작업을 “위임”하는 디자인 패턴이다.
- 해당 패턴에서는 한 객체(위임자, delegator)가 자신이 해야 할 일의 일부를 다른 객체(델리게이트, delegate)에게 위임합니다.
- 위임자(delegator)는 델리게이트(delegate)에게 자신의 이벤트나 상태 변화에 대해 알려주고, 델리게이트는 이에 대해 적절히 응답하게끔 한다.
- 아하 아까 위에서 상황을 생각해보면!
- UITextFieldDelegate가 위임자가 되고
- delegate는 ViewController가 되는 거다.
- UITextFieldDelegate가 위임자(Delegator):
- UITextField 객체가 UITextFieldDelegate 프로토콜을 정의하고 있으며
- 이 프로토콜을 통해 텍스트 필드와 관련된 이벤트(예: 텍스트 변경, 편집 시작 및 종료)를 처리할 수 있도록 위임한다.
- ViewController가 델리게이트(Delegate):
- ViewController는 UITextFieldDelegate 프로토콜을 채택하여, 텍스트 필드에서 발생하는 이벤트를 처리하는 역할을 맡고 있다.
- 즉, textField.delegate = self를 통해 UITextField의 델리게이트로 ViewController가 설정되었기 때문에, UITextField에서 발생하는 이벤트는 ViewController에 전달되어 처리된다.

요약
- UITextFieldDelegate에 등록되어 있는 프로토콜들을
- textField.delegate = self라는 코드를 통해, self를 의미하는 현재 클래스인 ViewController가 textField를 대신해서 동작 해준다는 의미
이런게 많은가?
- Delegate 패턴은 iOS 개발에서 매우 흔하게 사용된다.
- 예를 들어, UITableViewDelegate, UIScrollViewDelegate, UICollectionViewDelegate 등 다양한 Delegate 패턴이 존
- 이렇게 다양한 Delegate 패턴들이 사용자 인터페이스의 다양한 상호작용을 처리하기 위해 사용됨.
- Delegate 패턴은 하나의 객체가 다른 객체의 행동을 제어하거나 모니터링하는 데 사용되며, 객체 간의 결합도를 낮춰 코드의 재사용성과 확장성을 높인다
Delegate 패턴은 기존 만들어진 것들을 통해 사용하기도 하고, 우리가 직접 프로토콜을 만들어 만드는 경우도 많다고 한다.
그렇다면 한 번 만들어보자.
TV, TV를 조종할 수 있는 리모콘을 예시로 생각해보자.
[RemoteControlDelegate]
- 리모컨이 사용할 메서드들, 즉 channelUp()과 channelDown()을 정의
- 이 프로토콜은 리모컨과 리모컨이 조작할 기기 간의 커뮤니케이션 인터페이스를 정의
// 자격증(정의) -> (텍스트필드 프로토콜)와 역할이 같다.
protocol RemoteControlDelegate {
func channelUp()
func channelDown()
}
[RemoteControl]
- 리모콘 클래스는 아래와 같다.
- delegate 속성: 이 속성은 RemoteControlDelegate 프로토콜을 따르는 객체를 참조
- 직접적으로 유저와 커뮤니케이션이 가능한 녀석이다.
- 그저 delegate에 메시지를 전달하고, 실제 동작은 delegate가 처리
// 리모콘 클래스(텍스트필드의 역할 - 직접적으로 유저와 커뮤니케이션)
class RemoteControl {
// delegate 타입은 프로토콜 타입으로 정의가 되어 있음
// 나중에 어떤 녀석이 대리자가 될 지 결정할 수 있음.
var delegate: RemoteControlDelegate?
func doSomething() {
print("리모콘의 조작!!")
}
func channelUp() { // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨
// 대리자가 가지고 있는 channelUp을 함.
delegate?.channelUp()
}
func channelDown() { // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨
// 대리자가 가지고 있는 channelDown을 함.
delegate?.channelDown()
}
}
- TV도 만들어보자.
// TV 클래스(뷰컨트롤러의 역할 - 리모콘과 커뮤니케이션)
class TV: RemoteControlDelegate {
func channelUp() {
print("TV의 채널이 올라간다.")
}
func channelDown() {
print("TV의 채널이 내려간다.")
}
}
let remote = RemoteControl()
let samsungTV = TV()
// RemoteControl의 delegate에 samsungTV가 들어감.
remote.delegate = samsungTV
remote.channelUp() // 리모콘 실행 ====> delegate?.channelUp()
remote.channelDown() // 리모콘 실행 ====> delegate?.channelDown()
이와 같이 custom delegate pattern도 만들어서 적용시켜 볼 수도 있다.
이제 어떤 class, struct든, RemoteControlDelegate 프로토콜을 채택하기만 하면 리모콘의 기능을 쓸 수 있는 것이다.
'iOS > UIKit' 카테고리의 다른 글
UIKit에서의 MVC (1) | 2024.09.12 |
---|---|
ViewController 생명주기 (0) | 2024.08.21 |
UIKit이란? (0) | 2024.08.21 |
UIKit No.3 (0) | 2024.01.14 |
UIKit No.2 (0) | 2024.01.11 |
날짜: 2024년 8월 22일
태그: delegate, iOS

- 이와 같은 텍스트필드가 존재하는 View가 있다.
- 해당 텍스트필드는 해당 뷰컨트롤러(뷰)와는 분리된 또다른 객체이다.
- 유저와 직접적인 커뮤니케이션을 하는 부분으로
- 내부에서 키보드가 동작하며, 키보드는 OS의 관리 영역이다.
- 사용자가 어떠한 동작을 한 뒤에, 동작을 다시 뷰컨트롤러에 전달하는 커뮤니케이션 과정이 일어난다.
- 동작의 형태로는 디테일하게 여러가지가 존재한다.
- etc: 입력 시작, 종료, 변경 .. 등등
- 이와 별개로 버튼의 경우(추천, blue, red…)는 IBAction을 통해 뷰컨트롤러와 직접적인 커뮤니케이션이 가능하다.
즉, 정리해보면
- 텍스트필드는 유저와 커뮤니케이션을 따로 해준 뒤에
- 뷰컨트롤러에 동작을 전달해준다.

- 그러면 어떻게 코드로 할 수 있지?
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
@IBOutlet weak var suggestButton: UIButton!
let suggestNickName = ["AAAAA", "BBBB", "CCC", "DD", "E"]
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
setUp()
}
func setUp() {
textField.borderStyle = .line
nextButton.isEnabled = false // 초기 비활성화
teamCharacterImage.image = UIImage(named: "yellow")
}
@IBAction func suggestButtonTapped(_ sender: UIButton) {
if let randomNickname = suggestNickName.randomElement() {
textField.text = randomNickname
validateNickname()
}
}
}
extension ViewController: UITextFieldDelegate {
func textFieldDidChangeSelection(_ textField: UITextField) {
validateNickname()
}
private func validateNickname() {
guard let nickname = textField.text else {
nextButton.isEnabled = false
return
}
let nicknameRegex = "^(?=.*[a-zA-Z])[a-zA-Z0-9]{1,5}$"
let isValid = NSPredicate(format: "SELF MATCHES %@", nicknameRegex).evaluate(with: nickname)
nextButton.isEnabled = isValid
}
}
음… UITextField는 텍스트 필드구나… 하겠지만, UITextFieldDelegate 프로토콜은 뭐지?
UITextFieldDelegate | Apple Developer Documentation
UITextFieldDelegate | Apple Developer Documentation
A set of optional methods to manage editing and validating text in a text field object.
developer.apple.com
UITextField
protocol UITextFieldDelegate 텍스트 필드 객체의 텍스트 편집 및 유효성 검사를 관리하는데 사용하는 선택적인 메소드 집합
medium.com
[우선 공식문서의 설명은 다음과 같다]
A text field calls the methods of its delegate in response to important changes. You use these methods to validate text that was typed by the user, to respond to specific interactions with the keyboard, and to control the overall editing process. Editing begins shortly before the text field becomes the first responder and displays the keyboard (or its assigned input view).
[한글 해석]
textField
는 중요한 변화에 대응하여 델리게이트 메소드를 호출한다. 사용자가 입력한 텍스트를 검증하고, 키보드와의 특정 상호작용에 응답하며, 전체 편집 프로세스를 제어하는데 이 메소드들을 사용한다. 편집은 텍스트 필드가 first responder가 되기 직전 시작되고 키보드(또는 할당된 input view)를 표시한다.
- 난 영어를 잘 못한다…
- 간단히 말하면, 텍스트 필드 객체에서의 텍스트 편집, 유효성 검사를 관리하는데 사용하는 메소드 집합이다.
- First Responder가 뭔가?
- 이벤트를 처음 받는
responder
- 가장 우선순위가 높은
responder
이기도 하다.
- 이벤트를 처음 받는
- 메소드 집합에는 뭐가 있을까?
func textFieldShouldBeginEditing(_ textField: CustomTextField) -> Bool {
// 텍스트 필드에서 편집을 시작할지 말지의 여부를 delegate에게 확인하는 메서
// return false인 경우 편집되지 않음
return true
}
func textFieldDidBeginEditing(_ textField: CustomTextField) {
// 텍스트 필드에서 입력이 시작되었음을 delegate에게 알려주는 메서
// 텍스트 필드 편집 중에 일어나는 메서드
}
func textFieldShouldEndEditing(_ textField: CustomTextField) {
// 텍스트 필드에서 입력을 중지할지 말지의 여부를 delegate에게 확인하는 메서드
}
func textFieldDidEndEditing(_ textField: CustomTextField) {
// 텍스트 필드에서의 입력이 중지되는 시점과 중지된 이유를 delegate에게 알려주는 메서드
}
func textFieldDidEndEditing(_ textField: CustomTextField, reason: CustomTextField.DidEndEditingReason) {
// 텍스트 필드에서 입력이 중지되는 시점을 delegate에게 알려주는 메서드
}
func textField(_ textField: CustomTextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
// 텍스트 필드의 입력값이 변경될지의 여부를 delegate에게 묻는 메서드
// textfield에 입력될 때마다 호출되는 함수
// 텍스트 필드 내용이 변경될 때 호출 (입력할 수 있는 텍스트의 길이도 정할 수 있다)
return false
}
func textFieldDidChangeSelection(_ textField: CustomTextField) {
// 텍스트 필드에서 텍스트 선택이 변경되면 delegate에게 알려주는 메서드
}
func textFieldShouldClear(_ textField: CustomTextField) -> Bool {
// 텍스트 필드에 입력된 것들을 지울지의 여부를 delegate에게 묻는 메서드
// 텍스트 필드의 내용이 삭제될 때 호출
return false // false 리턴 시 삭제되지 않음
}
func textField(_ textField: CustomTextField, editMenuForCharactersIn range: NSRange, suggestedActions: [UIMenuElement]) -> UIMenu? {
// 시스템이 제공하는 텍스트 범위 및 action을 기반으로 텍스트 필드에 표시할 메뉴를 delegate에게 요청하는 메서드
return nil
}
@available(iOS 16.0, *)
func textField(_ textField: CustomTextField, willPresentEditMenuWith animator: UIEditMenuInteractionAnimating) {
}
@available(iOS 16.0, *)
func textField(_ textField: CustomTextField, willDismissEditMenuWith animator: UIEditMenuInteractionAnimating) {
}
뭐 대충 어떤 느낌인지… 뭐가 있는 지도 알겠다.
그런데 Delegate라는 게 여전히 감이 안 잡힌다…
[우선 단어의 의미부터 보자]
Delegate?
- 대리자, 대표
[그럼 델리게이트 패턴은 뭐지?]
Delegate Pattern?
[객체와 객체간의 커뮤니케이션을 위한 패턴]
[커뮤니케이션은 프로토콜을 통해 진행된다.]
즉..!
- Delegate 패턴은 하나의 객체가 다른 객체에 특정 작업을 “위임”하는 디자인 패턴이다.
- 해당 패턴에서는 한 객체(위임자, delegator)가 자신이 해야 할 일의 일부를 다른 객체(델리게이트, delegate)에게 위임합니다.
- 위임자(delegator)는 델리게이트(delegate)에게 자신의 이벤트나 상태 변화에 대해 알려주고, 델리게이트는 이에 대해 적절히 응답하게끔 한다.
- 아하 아까 위에서 상황을 생각해보면!
- UITextFieldDelegate가 위임자가 되고
- delegate는 ViewController가 되는 거다.
- UITextFieldDelegate가 위임자(Delegator):
- UITextField 객체가 UITextFieldDelegate 프로토콜을 정의하고 있으며
- 이 프로토콜을 통해 텍스트 필드와 관련된 이벤트(예: 텍스트 변경, 편집 시작 및 종료)를 처리할 수 있도록 위임한다.
- ViewController가 델리게이트(Delegate):
- ViewController는 UITextFieldDelegate 프로토콜을 채택하여, 텍스트 필드에서 발생하는 이벤트를 처리하는 역할을 맡고 있다.
- 즉, textField.delegate = self를 통해 UITextField의 델리게이트로 ViewController가 설정되었기 때문에, UITextField에서 발생하는 이벤트는 ViewController에 전달되어 처리된다.

요약
- UITextFieldDelegate에 등록되어 있는 프로토콜들을
- textField.delegate = self라는 코드를 통해, self를 의미하는 현재 클래스인 ViewController가 textField를 대신해서 동작 해준다는 의미
이런게 많은가?
- Delegate 패턴은 iOS 개발에서 매우 흔하게 사용된다.
- 예를 들어, UITableViewDelegate, UIScrollViewDelegate, UICollectionViewDelegate 등 다양한 Delegate 패턴이 존
- 이렇게 다양한 Delegate 패턴들이 사용자 인터페이스의 다양한 상호작용을 처리하기 위해 사용됨.
- Delegate 패턴은 하나의 객체가 다른 객체의 행동을 제어하거나 모니터링하는 데 사용되며, 객체 간의 결합도를 낮춰 코드의 재사용성과 확장성을 높인다
Delegate 패턴은 기존 만들어진 것들을 통해 사용하기도 하고, 우리가 직접 프로토콜을 만들어 만드는 경우도 많다고 한다.
그렇다면 한 번 만들어보자.
TV, TV를 조종할 수 있는 리모콘을 예시로 생각해보자.
[RemoteControlDelegate]
- 리모컨이 사용할 메서드들, 즉 channelUp()과 channelDown()을 정의
- 이 프로토콜은 리모컨과 리모컨이 조작할 기기 간의 커뮤니케이션 인터페이스를 정의
// 자격증(정의) -> (텍스트필드 프로토콜)와 역할이 같다.
protocol RemoteControlDelegate {
func channelUp()
func channelDown()
}
[RemoteControl]
- 리모콘 클래스는 아래와 같다.
- delegate 속성: 이 속성은 RemoteControlDelegate 프로토콜을 따르는 객체를 참조
- 직접적으로 유저와 커뮤니케이션이 가능한 녀석이다.
- 그저 delegate에 메시지를 전달하고, 실제 동작은 delegate가 처리
// 리모콘 클래스(텍스트필드의 역할 - 직접적으로 유저와 커뮤니케이션)
class RemoteControl {
// delegate 타입은 프로토콜 타입으로 정의가 되어 있음
// 나중에 어떤 녀석이 대리자가 될 지 결정할 수 있음.
var delegate: RemoteControlDelegate?
func doSomething() {
print("리모콘의 조작!!")
}
func channelUp() { // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨
// 대리자가 가지고 있는 channelUp을 함.
delegate?.channelUp()
}
func channelDown() { // 어떤 기기가 리모콘에 의해 작동되는지 몰라도 됨
// 대리자가 가지고 있는 channelDown을 함.
delegate?.channelDown()
}
}
- TV도 만들어보자.
// TV 클래스(뷰컨트롤러의 역할 - 리모콘과 커뮤니케이션)
class TV: RemoteControlDelegate {
func channelUp() {
print("TV의 채널이 올라간다.")
}
func channelDown() {
print("TV의 채널이 내려간다.")
}
}
let remote = RemoteControl()
let samsungTV = TV()
// RemoteControl의 delegate에 samsungTV가 들어감.
remote.delegate = samsungTV
remote.channelUp() // 리모콘 실행 ====> delegate?.channelUp()
remote.channelDown() // 리모콘 실행 ====> delegate?.channelDown()
이와 같이 custom delegate pattern도 만들어서 적용시켜 볼 수도 있다.
이제 어떤 class, struct든, RemoteControlDelegate 프로토콜을 채택하기만 하면 리모콘의 기능을 쓸 수 있는 것이다.
'iOS > UIKit' 카테고리의 다른 글
UIKit에서의 MVC (1) | 2024.09.12 |
---|---|
ViewController 생명주기 (0) | 2024.08.21 |
UIKit이란? (0) | 2024.08.21 |
UIKit No.3 (0) | 2024.01.14 |
UIKit No.2 (0) | 2024.01.11 |