-
Delegate 패턴iOS 앱 2023. 3. 31. 19:24
Delegate 패턴은 왜 사용하는가?
: Delegate(대리자), 직접 행동하는 것이 아닌, 해야 할 행동을 위임한다.
1. 두 객체의 소통을 위한 delegate pattern
두 객체를 연결해 주고 싶을 때 사용
-> 이벤트를 받은 객체와 이를 처리할 객체가 다른 경우에 사용한다.
2. UI요소에서의 delegate pattern
인스턴스가 직접적으로 행위를 실행하기 어려운 경우에 사용한다. UI요소의 경우에는 직접 내부 코드를 수정할 수 없는 경우에 사용한다.
UITableview의 내부 코드는 숨겨져있다.
따라서, delegate를 지정하고, 이 delegate에서 할 행동을 선언해주어야한다.
Delegate 패턴 예시
protocol Remotecontrol{ func chanelUp() } class RemoteController { var delegate : Remotecontrol? func remoteControllerChanelUp() { delegate?.chanelUp() } } class TV : Remotecontrol { func chanelUp() { print("TV chanel Up") } } let remote = RemoteController() let samTV = TV() remote.delegate = samTV remote.remoteControllerChanelUp() // ("TV chanel Up")출력
리모컨이 TV의 채널을 올리는 상황,
TV는 리모컨의 명령을 받을 수 있는 단자가 필요하다.
이때, 리모컨을 인식할 수 있는 형식임을 Protocol로 보증.
Protocol로 TV가 해야 하는 행동을 나열한다.
위 코드에서는 chanelUp()
chanelU메서드 구현은 TV 클래스에서 해주어야한다.
TV는 chanelUp() 메서드가 실행된 경우 어떤 행동을 할지 정의한다.
리모컨은 delegate 프로퍼티로 samTV 선언
remote.delegate = samTV
리모컨에서
remoteControllerChanelUp() 메서드 실행시,
samTV의
chanelUp() 매서드가 실행된다.
remote.remoteControllerChanelUp()
delegate pattern 사용시 주의사항: 강한 참조 순환(Strong Reference Cycle)
: delegate 프로퍼티 정의 시 weak으로 선언 필요 (서로를 참조하는 경우)
class RemoteController { //⭐️weak으로 선언 weak var delegate : Remotecontrol? func remoteControllerChanelUp() { delegate?.chanelUp() } }
UITextFieldDelegate 사용 예시
import UIKit //뷰컨트롤러에서 UITextFieldDelegate 채택 class ViewController: UIViewController, UITextFieldDelegate { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() //delegate설정, 여기서의 self는 viewcontroller를 의미 textField.delegate = self setup() } func setup() { textField.keyboardType = UIKeyboardType.emailAddress textField.placeholder = "이메일 입력" textField.borderStyle = .roundedRect textField.clearButtonMode = .always textField.returnKeyType = .go } //텍스트 필드의 입력을 시작할 때 호출 (시작할지 말지의 여부 허락하는 것) func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool { return true } // 시점 - 텍스트 필드의 입력이 시작되는 시점 func textFieldDidBeginEditing(_ textField: UITextField) { print("유저가 텍스트 필드의 입력을 시작함.") } func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let maxLength = 10 let currentString: NSString = (textField.text ?? "") as NSString let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString return newString.length <= maxLength } @IBAction func inputbtnPressed(_ sender: UIButton) { print(textField.text) textField.text = "" } }
textField가 ViewController에게 행동을 위임함.
textField에서 어떤 행동이 일어났을때 이를 ViewController에 알린다.
:ViewController가 textField의 delegate가 된다.
textField.delegate = self
textField -> 리모컨
ViewController -> TV
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { let maxLength = 10 let currentString: NSString = (textField.text ?? "") as NSString let newString: NSString = currentString.replacingCharacters(in: range, with: string) as NSString return newString.length <= maxLength }
textField에서 사용자의 입력이 시작된 것을 ViewController에 알리고,
이를 바탕으로 ViewController는 메서드(textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool)를 실행시켜서 Bool타입을 반환한다.
이 때, Bool타입인 false가 오면 textField는 입력을 막는다.