delegate를 설명하기전에 protocol에 대해서 알아야한다.
왜냐하면 delegate는 protocol로 구현되기 때문이다.
protocol은 특정 역할을 하기 위한 메소드, 프로퍼티, 기타 요구사항 등의 청사진을 의미 합니다.
일상생활에서 붕어빵을 예시로 들어볼게요.
붕어빵을 만들기 위해서는
붕어빵 기계의 틀, 반죽, 불 등이 필요하죠.
그리고 붕어빵에는 팥붕, 슈붕등 여러가지가 있습니다.
팥붕, 슈붕 모두 만들기 위해서는 붕어빵 기계를 가지고 있어야 하죠.
즉, 붕어빵을 만들기 위해 꼭 필요한 붕어빵 기계가 protocol이라고 할 수 있습니다.
그리고 붕어빵을 만들기 위해 틀, 반죽, 불 등을 모두 구현해야 합니다.
하지만 팥붕이나 슈붕은 다른 붕어빵 입니다.
이를, 붕어빵 기계라는 protocol의 틀, 반죽, 불 등을 다르게 해서 구현해야 해요.
즉, protocol은 기능을 구현하는 것이 아니라, 선언만 해야합니다.
protocol에 대해서 간단히 설명 하였으니, 이제 delegate가 무엇인지 알아봅시다.
delegate는 사전적 의미로 대리자, 위임자로 해석됩니다.
swift에서는 delegate를 통해 특정 기능을 위임하는 것 입니다.
말로 설명하는 것보다 예제코드로 알아봅시다.
두 개의 뷰컨트롤러(A, B)가 있고
A 에서 B로 이동한 후, 다시 A로 돌아갈 때
데이터를 전달 하고자 합니다.
이 때, delegate를 이용해서 데이터를 넘길 수 있습니다.
우선 저는 화면 구성을 아래 처럼 했습니다.
몇 번쨰 화면인지 나타내는 label과 전달 받은 데이터를 표시할 label, 그리고 전달할 데이터를 입력할 textField,
화면을 전환하기 위해 필요한 button을 두개 만들었습니다.
첫 번째 화면에서 Next 버튼을 클릭하면 두 번째 화면이 나타나고,
textField에 전달할 값을 입력한 뒤 Done버튼을 클릭하면 첫 번째 화면으로 돌아갑니다.
그리고 전달 받은 데이터가 label에 표시 되도록 하겠습니다.
우선 delegate 패턴을 적용하려면 protocol을 만들어야 합니다.
protocol DeliveryDataProtocol: AnyObject {
func deliveryData(data: String)
}
전달할 데이터를 textField에 입력해 넘겨줄거기 때문에 위와같이
AnyObject를 상속한 프로토콜을 간단하게 만들었습니다.
class ViewController: UIViewController, DeliveryDataProtocol {
@IBOutlet weak var label: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
func deliveryData(data: String) {
label.text = data
}
@IBAction func nextView(_ sender: UIButton) {
guard let secondVC = self.storyboard?.instantiateViewController(withIdentifier: "SecondViewController") as? SecondViewController else { return }
secondVC.delegate = self
self.present(secondVC, animated: true)
}
}
delegate 패턴에서 data를 전달받을 화면에 작성한 protocol을 위와 같이 채택해 주어야합니다.
protocol을 채택했다면 해당 protocol을 준수하여야 하기 때문에 첫 번째 화면에 deliveryData함수를 구현해 줍니다.
그리고 Next버튼을 클릭했을 때 두 번째 화면이 나오도록 함수를 만들었습니다.
화면이 이동할 때 가장 중요한 대리자가 나 라는걸 명시해줘야 합니다.
class SecondViewController: UIViewController {
//...
weak var delegate: DeliveryDataProtocol?
//...
}
두 번째 화면에서는 DeliveryDataProtocol 타입의 프로퍼티를 위와 같이 선언 해줍니다.
위 코드에서 weak를 쓴 이유는 weak를 쓰지않고 화면이동이 일어날 경우 메모리에서 해제되지 않기 때문에 사용해줍니다.
처음 protocol을 선언할 때 AnyObject를 상속한 이유가 바로 이것입니다.
사실 AnyObject 말고도 class를 상속할 경우에도 프로퍼티를 선언할 때 weak를 사용할 수 있습니다.
반대로 AnyObject나 class를 상속하지 않은 protocol인 경우에는 weak를 사용할 수 없습니다.
class SecondViewController: UIViewController {
@IBOutlet weak var textField: UITextField!
weak var delegate: DeliveryDataProtocol?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
@IBAction func DoneBtnClick(_ sender: UIButton) {
delegate?.deliveryData(data: textField.text ?? "")
self.dismiss(animated: true)
}
}
위와 같이, 두 번째 화면에서 Done버튼을 클릭할 때
delegate로 선언한 deliveryData함수의 인자를 textField에 입력한 값으로 작성하고,
첫 번째 화면으로 넘겨줍니다.
설명을 잘 따라 오셨다면 아래와 같이 완성된 화면을 볼 수 있습니다!