-
Delegate 패턴iOS 2021. 8. 28. 16:28
목차
1. Delegate 패턴 정의
2. Delegate 패턴 예시
3. 결론
Delegate 패턴 정의
delegate란 "위임하다, 대리하다"라는 뜻을 가집니다. 영어 뜻에서도 살펴볼 수 있듯이 delegate 패턴이란 객체 A가 할 일을 객체 B에게 맡기는 것입니다. 즉 본인이 할 일을 다른 객체에게 위임하는 것입니다. 다양한 방법으로 사용될 수 있겠지만 간단하게 예를 들자면, 서브뷰가 클릭 되었을 때의 동작을 슈퍼뷰가 대신 하는 것입니다. 서브뷰가 슈퍼뷰에게 자신이 할 일을 위임하는 것입니다. 예시를 통해 알아보겠습니다.
Delegate 패턴 예시
동작 모습
커스텀뷰(회색)가 클릭되면 뷰컨트롤러의 레이블이 나타난다. (정확히 말하면 뷰컨트롤러의 레이블 텍스트컬러를 검은색을 변경) 먼저 커스텀뷰 코드를 살펴보겠습니다.
// CustomView.swift // DelegateExample import Foundation import UIKit //Delegate 패턴을 위한 프로토콜 protocol CustomViewDelegate { func touch() -> Void } class CustomView: UIView { //위임할 객체가 담길 delegate 변수 var delegate: CustomViewDelegate? override init(frame: CGRect) { super.init(frame: frame) setupView() } required init?(coder: NSCoder) { super.init(coder: coder) setupView() } func setupView() { self.backgroundColor = .darkGray } //CustomView가 터치되면 delegate의 touch 함수 호출 override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { delegate?.touch() } }
CustomViewDelegate 프로토콜이 정의되어있는 곳을 보면 touch 함수가 있습니다. CustomView 클래스에서는 CustomViewDelegate를 채택하는 변수 delegate를 통해 touch 함수를 호출합니다. 이를 통해 delegate 변수에 담긴 객체에서 touch 함수가 실행될 수 있습니다. delegate 변수에 뷰컨트롤러를 할당한다면 결국 delegate는 뷰컨트롤러를 가리키게 되고 delegate?.touch 를 호출한다면 뷰컨트롤러에서 touch를 호출하는 것과 같습니다. delegate 변수에 뷰컨트롤러를 할당하는 것은 다음에 나올 뷰컨트롤러 부분에 쓰여있습니다.
// ViewController.swift import UIKit class ViewController: UIViewController, CustomViewDelegate { var csView = CustomView() //클릭될 커스텀뷰 (회색 박스) var label = UILabel() //커스텀뷰가 클릭되면 나타날 문구 override func viewDidLoad() { super.viewDidLoad() setupVC() } func setupVC() { self.view.addSubview(csView) self.view.addSubview(label) csView.translatesAutoresizingMaskIntoConstraints = false csView.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.7).isActive = true csView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.2).isActive = true csView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true csView.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true csView.backgroundColor = .darkGray label.translatesAutoresizingMaskIntoConstraints = false label.widthAnchor.constraint(equalTo: self.view.widthAnchor, multiplier: 0.7).isActive = true label.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 0.1).isActive = true label.topAnchor.constraint(equalTo: csView.bottomAnchor, constant: 100).isActive = true label.centerXAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.centerXAnchor).isActive = true label.text = "Custom View is Clicked!" label.textAlignment = .center label.font = UIFont.systemFont(ofSize: 20) label.textColor = .white //Delegate 패턴의 핵심 부분 csView.delegate = self //커스텀뷰의 delegate를 self(뷰 컨트롤러)로 지정 } //CustomViewDelegate 프로토콜을 구현하기 위해서 필요한 함수 //touch 함수는 ViewController에서 직접 호출하는 함수가 아니고 delegate에 의해 자동으로 호출되는 함수 func touch() { label.textColor = .black } }
일단 클래스 선언부에 CustomViewDelegate를 채택하는 것을 볼 수 있습니다. 이를 통해 CustomView의 delegate 변수에 뷰컨트롤러가 할당 될 수 있습니다(정말 할당 되었다는 말이 아니고 CustomViewDelegate를 요구하는 변수 delegate에 뷰컨트롤러가 할당 되어도 오류가 나지 않는다는 말입니다). 더군다나, 해당 프로토콜을 구현함으로써 CustomView가 위임할 동작들을 뷰컨트롤러에서 하게 되는 것입니다. touch 함수가 정의된 부분을 보시면 label의 텍스트 색을 검은색으로 변경함으로써 CustomView가 클릭되었다는 것을 알 수 있게 됩니다. 그리고 앞에서 언급했듯이, 이 모든 것은 뷰컨트롤러를 CustomView의 delegate 변수에 할당함으로써 가능하게 됩니다. 'csView.delegate = self' 를 살펴보면 "csView의 일을 위임받을 객체는 self" 라는 의미로 볼 수 있습니다. 어찌보면 도움을 구하는 객체의 일을 자신이 한다고 나서는 모습이라고 표현할 수도 있을 것 같습니다.
결론
델리게이트 패턴은 디자인 패턴 중 빈번하게 쓰이는 것 같습니다. 특히 iOS 에서는 더욱 많이 쓰이는 것 같습니다. 타이머 앱을 만들며 뷰컨트롤러에 삽입된 타이머뷰를 눌렀을 때 타이머가 멈추게 하는 동작을 구현하고 싶었는데 델리게이트 패턴으로 손쉽게 구현할 수 있었습니다. 물론 델리게이트 패턴없이 값을 전달하며 동작을 구현할 수도 있겠지만 이 패턴을 구현한다면 확장성에 장점이 있다고 알고 있습니다.
'iOS' 카테고리의 다른 글
[출시를 향한 여정] 타이머 어플 - 3. LED 플래시를 통해 알림받기 (0) 2021.10.23 [출시를 향한 여정] 타이머 어플 - 2. 시간 설정, 백그라운드/포그라운드 전환 구현 (0) 2021.10.03 [iOS] GCD : 1. 동시성(Concurrency) 프로그래밍 (0) 2021.09.18 [iOS] View Controller의 생명주기 (0) 2021.09.04 [출시를 향한 여정] 타이머 어플 - 1. 타이머 어플을 만드려는 이유 (0) 2021.08.15