iOS - Delegate Pattern

longlivedrgn·2023년 1월 11일
0

iOS

목록 보기
6/10
post-thumbnail

Delegate Pattern

  • 두 개의 클래스 A,B가 존재한다고 가정해보자. 만약 A에서 B의 어떠한 프로퍼티 값을 고치고 싶다면? 혹은 A에서 B로 데이터를 옮기고 싶다면? 우리는 Delegate Pattern을 사용해 볼 수 있다.

☀️ Delegate Pattern 예시(1)

TeachercleaningArea 프로퍼티를 가지고 있고, StudentTeachercleaningArea 값을 변화시킨다. 해당 과정을 delegate pattern을 통하여 구현해보자.

  • ViewController간의 데이터 전달이 아닌, 일반 클래스 간의 데이터 전달의 예를 알아보자. 아래와 같은 protocol을 생성해보자.
// 청소를 시킬 수 있는
protocol CleanOrderable {
    var cleaningArea: [String: Bool] { get set }
    func notifyTodayCleanArea() -> [String]
}
  • 아래와 같이 TeacherCleanOrderable 프로토콜을 채택하였기에 함수의 바디를 작성해주어야된다.
class Teacher: CleanOrderable {
    var cleaningArea: [String : Bool]
    var myClass: String
    
    init(area: [String : Bool], myClass: String) {
        self.cleaningArea = area
        self.myClass = myClass
    }
    // 자신(teacher)의 cleaningArea를 던지는 함수
    func notifyTodayCleanArea() -> [String] {
        return cleaningArea.keys.map { String($0) }
    }
}
  • 그리고 Studentdeleagate 변수를 하나 생성해준다.
    • 여기서 delegate은 결국 teacher로 바꿔치기된다.
    • 즉, StudentTeacher의 함수를 호출하여 TeachercleaningArea의 값을 변경한다.
class Student {
    var delegate: CleanOrderable?
    
    func clean() {
        let todayCleanTargetArea = delegate?.notifyTodayCleanArea()
        
        todayCleanTargetArea?.forEach { area in
            delegate?.cleaningArea.updateValue(true, forKey: area)
        }
    }
}
  • 그리고 여기서 가장 중요한 점은 생성한 Student 객체의 delegate 변수를 teacher로 설정해주는 것이다. 그러면 최종적으로 delegateteacher로 바꿔치기되는 것이다!
let teacher = Teacher(area: ["복도": false, "교실": false], myClass: "1반")
let student = Student()
student.delegate = teacher
student.clean()
teacher.cleaningArea // ["복도": true, "교실": true]

원래는 tudentTeachercleaningArea를 변경하려면, Student안에 Teacher를 프로퍼티로 가져서 변경해주면 되지만, 위와 같이 delegate pattern을 통하여 해결을 할 수 있다.

☀️ Delegate Pattern 예시 (2) - ViewController간의 데이터 전달

  • 아래의 그림과 같이 SendViewController에서 ReceiveViewController로 데이터 전달을 delegate pattern을 통하여 해보자.

SendViewController의 textfield에 글을 쓰고 button을 누르면 dismiss가 되면서 textfield에 있는 text가 ReceiveviewController의 label에 나오게 된다.

  • 아래와 같이 protocol을 하나 생성해준다.
protocol SendDataDelegate {
    func sendData(data: String)
}
  • 그리고 SendViewController에 delegate 변수를 하나 생성해준다. 그리고 delegate?.sendData를 통하여 원하는 데이터를 담아서 보낸다.- 실제로 함수를 실행하는 부분. (delegate는 ReceiveViewController로 바꿔치기된다.)
class SendViewController: UIViewController {
    
    var delegate: SendDataDelegate?

    @IBOutlet weak var myTextField: UITextField!
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func myButtonClicked(_ sender: Any) {
        guard let data = myTextField.text else { return }
        **delegate?.sendData(data: data)**
        dismiss(animated: true, completion: nil)
    }
}
  • ReceiveViewController에서는 sendViewController에서 선언한 Delegate이 자신(ReceiveViewController)임을 선언하고, SendDataDelegate을 채택하여 sendData 함수의 바디를 완성해준다.(실질적인 함수 실행은 SendViewController에서 진행된다.)
class ReceiveViewController: UIViewController {
    
    @IBOutlet weak var myLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Do any additional setup after loading the view.
    }
    
    @IBAction func plusButtonCliecked(_ sender: Any) {
        guard let sendViewController = self.storyboard?.instantiateViewController(withIdentifier: "SendViewController") as? SendViewController else { return }
        **sendViewController.delegate = self**
        present(sendViewController, animated: true)
    }
    
}

extension ReceiveViewController: **SendDataDelegate** {
    func sendData(data: String) {
        **myLabel.text = data**
    }
}

🔥 총정리

만약 A,B 두개의 ViewController가 존재하고 B의 데이터를 A에게 전달하고 싶다면?

ViewController A ( 데이터를 전달 받는)

  • protocol을 채택(protocol 내의 함수를 완성시켜주어야된다.)
  • ViewController B 안의 delegate 변수의 위임자가 자신임을 선언해준다.
    • ex) viewControllerB.delegate = self

ViewController B (데이터를 전달하는)

  • delegate 변수를 선언해준다.
    • ex) var delegate: ProtocolName?
  • 실제 함수를 발동시키는 코드를 작성한다.
    • delegate?.protocolFunc()

0개의 댓글