본문 바로가기
Swift

델리게이트 패턴이란?

by 밤새는 탐험가89 2024. 7. 8.
728x90
SMALL

Delegate Pattern 이란?

 

"객체가 자신의 책임을 다른 객체에게 위임(delegate)하는 디자인 패턴"을 의미한다.

 

예를 들어, 테이블뷰 또는 컬렉션 뷰를 사용할 때 어떤 액션을 취할지에 대한 책임을 

뷰컨트롤러에게 UITableViewDelegate 또는 UICollectionViewDelegate를 사용하여 위임한다. 

 

그럼 왜 굳이 "위임"이라는 것을 사용하는 것일까?

 

애플이 미리 구현해 놓은 UITableView 또는 UICollectionView 등의

내부 코드는 비공개이기 때문에 개발자가 이를 알 수 없고, 그렇기에 수정할 수도 없다. 

 

위에서 예를 든 테이블의 셀을 탭했을때, 상황에 맞는 리액션을 개발자가 코드로 작성해야 한다. 

하지만 개발자는 애플이 구현해 놓은 내부 코드를 수정할 수 없다. 

따라서 다른 객체에서 개발자가 구현할 코드를 작성한 뒤에 

테이블뷰가 그 객체를 호출하는 방식을 사용한다. 

 

즉, 테이블뷰와 객체를 연결하는 방식이 바로 Delegate Pattern 이다. 

 

Delegate Pattern의 핵심은 두 객체를 연결하는 것이다. 

 

이벤트를 받는 객체 (예: UITableView)가 이벤트를 받아 

어떤 리액션을 취할지를 delegate (예: ViewController)에게 위임한다.

 

정리하면 delegate는 어떤 객체가 이벤트를 만났을 때, 그 객체를 대신하는 것을 말하고, 

delegating 객체는 이벤트를 받고 처리하는 responder 객체이다. 

 

 

실제로 앱에서는 어떤 방식으로 사용되나?

 

Delegate Pattern을 가장 많이 사용하는 경우는 두 개의 뷰컨트롤러 사이에 데이터를 전달할 때다.

 

예를 들어 사용자 프로필 수정창에서 사용자 정보를 수정하고 확인 버튼을 누르면

이전 화면으로 돌아가고, 이 때 입력받은 정보들을 보여줘야하는 경우에 사용한다. 

 

 

그럼 어떻게 사용하나?

ProfileViewController 화면이 밑에 있는 상태에서 그 위에 EditProfileViewController 화면이 올라오고, 

EditProfileViewController 에서 수정한 값을 ProfileViewController로 전달하고, 

EditProfileViewController 화면은 해제된다. 

 

1. 먼저 프로토콜을 생성한다. 

 

별도의 스위프트 파일을 생성하여 그 파일 내에 프로토콜을 생성한다. 

 

changeNameDelegate 라는 요리법을 가이드라인만 잡는다.

 

protocol changeNameDelegate {
    
    func changeName(name: String)
    
}

 

 

2. ProfileViewController 클래스 내에 위에 생성한 프로토콜을 채택한다.

ProfileViewController 가 바로 요리사라고 생각해보자 

class ProfileViewController: UIViewController, changeNameDelegate {
	...
}

 

 

3. ProfileViewController 클래스 내에 프로토콜을 채택할 경우, 

프로토콜 내의 함수를 구체적으로 구현한다.

 

 

changeName은 name이라는 파라미터를 profileView 내의 nameTextField의 값에 대입한다. 

 

ProfileViewController가 요리사 이기 때문에 요리법에 대해 제대로 알 필요가 있다. 

 

class ProfileViewController: UIViewController, changeNameDelegate {
    
    func changeName(name: String) {
        profileView.nameTextField.text = name
    }
    
    var profileView = ProfileView()
    ...
}

 

 

4. EditProfileViewController 파일 내에 코드를 구현한다. 

 

 4.1 delegate 변수를 선언한다. 

 

EditProfileViewController에 delegate라는 주문서를 생성한다. 

 

var delegate: changeNameDelegate?

 

 

 4.2 didTapButton() 메서드 내에서 delegate를 통해 프로토콜 내의 함수에 접근한다. 

 

changedName이라는 변수에 nameTextField 내의 입력한 값을 할당한다. 

그리고 delegate.changeName에 changeName을 전달한다. 

dismiss를 통해 EditProfileViewController를 제거한다. (이전 화면으로 돌아간다.)

 

delegate?.changeName(name: changeName) 이라는 주문서를 전달한다. 

 

@objc private func didTapButton() {
    changedName = editView.nameTextField.text ?? "잘못입력"
    delegate?.changeName(name: changedName)
    dismiss(animated: true)
}

 

 

 4.3 EditProfileViewController 내의 전체 코드 

 

class EditProfileViewController: UIViewController{
    
    var delegate: changeNameDelegate?
    
    var editView = EditView()
    
    var changedName: String = ""

    override func loadView() {
        self.view = editView
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        
        editView.editButton.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
    }
    
    @objc private func didTapButton() {
        changedName = editView.nameTextField.text ?? "잘못입력"
        delegate?.changeName(name: changedName)
        dismiss(animated: true)
    }

}



5. 마지막으로 ProfileViewController 클래스 내에서 

didTapButton() 메서드에 아래코드를 구현한다. 

 

여기서 "editVC.delegate = self" 라는 의미는 editVC의 대리자를 

ProfileViewController로 선언한다는 것이다. 

 

editVC.delegate = self 라고 주문서를 확인한다. 

 

@objc private func didTapButton() {
        let editVC = EditProfileViewController()
        editVC.modalPresentationStyle = .fullScreen
        editVC.delegate = self
    
        present(editVC, animated: true)
    }

 

 

 

 

Delegate로 데이터 전달을 사용하는 경우

 

 두 개의 화면이 있다. 두 번째 화면에서 데이터를 첫 번째 화면으로 옮길 때, 

이미 메모리에 올라와 있는 상태에서 데이터 전달 할 때 사용한다.

 

즉, 첫 번째 화면 위로 두 번째 화면을 올리고, 두 번째 화면에 첫 번째 화면으로 present를 통해 

데이터를 전달할 때 사용한다. 

 

또는 A 라는 뷰 컨트롤러 위에 TableViewCell, CollectionViewCell 를 올릴 때, 

이를 갖고 있는 상위 뷰 컨트롤러로 데이터를 전달할 때 사용한다. 

 

 

⭐️ 주의할 점이 하나 있다. 바로 Strong Reference Cycle 이다. 

 

사실 위에서 delegate 프로퍼티를 정의할 때 weak로 선언해야 한다. 

 

이유는 두 개의 클래스 (ProfileViewController, EditProfileViewController) 사이에서 

델리게이트 패턴을 사용할 경우 Strong Reference Cycle이 생길 수 있기 때문이다. 

728x90
LIST