ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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를 채택하는 것을 볼 수 있습니다. 이를 통해 CustomViewdelegate 변수에 뷰컨트롤러가 할당 될 수 있습니다(정말 할당 되었다는 말이 아니고 CustomViewDelegate를 요구하는 변수 delegate에 뷰컨트롤러가 할당 되어도 오류가 나지 않는다는 말입니다). 더군다나, 해당 프로토콜을 구현함으로써 CustomView가 위임할 동작들을 뷰컨트롤러에서 하게 되는 것입니다. touch 함수가 정의된 부분을 보시면 label의 텍스트 색을 검은색으로 변경함으로써 CustomView가 클릭되었다는 것을 알 수 있게 됩니다. 그리고 앞에서 언급했듯이, 이 모든 것은 뷰컨트롤러를 CustomViewdelegate 변수에 할당함으로써 가능하게 됩니다. 'csView.delegate = self' 를 살펴보면 "csView의 일을 위임받을 객체는 self" 라는 의미로 볼 수 있습니다. 어찌보면 도움을 구하는 객체의 일을 자신이 한다고 나서는 모습이라고 표현할 수도 있을 것 같습니다.

     


    결론

    델리게이트 패턴은 디자인 패턴 중 빈번하게 쓰이는 것 같습니다. 특히 iOS 에서는 더욱 많이 쓰이는 것 같습니다. 타이머 앱을 만들며 뷰컨트롤러에 삽입된 타이머뷰를 눌렀을 때 타이머가 멈추게 하는 동작을 구현하고 싶었는데 델리게이트 패턴으로 손쉽게 구현할 수 있었습니다. 물론 델리게이트 패턴없이 값을 전달하며 동작을 구현할 수도 있겠지만 이 패턴을 구현한다면 확장성에 장점이 있다고 알고 있습니다.

     

Designed by Tistory.