다음 View Controller에 데이터를 전달하고, 돌아가는 화면에 데이터를 전달하는 방법을 배운다.
Code로 전환한 뷰로 전달, Segue로 전달한 뷰로 전달하는 방법 중에 편한 방법을 사용하면 된다.
Code로 전환한 뷰 컨트롤러에서 데이터 전달하기
앱 테스팅을 위해서 데이터를 전달할 뷰 컨트롤러에 라벨을 추가한다.
스토리보드에서 이동할 뷰 컨트롤러에 라벨을 추가하고, Assistant를 통해서 코드를 관리한다.
class CodePushViewController: UIViewController {
@IBOutlet weak var nameLabel: UILabel!
var name : String?
override func viewDidLoad() {
super.viewDidLoad()
if let name = name {
self.nameLabel.text = name
self.nameLabel.sizeToFit()
}
}
@IBAction func tabBackButton(_ sender: UIButton) {
self.navigationController?
.popViewController(animated: true)
}
}
nameLabel : 전달 받은 데이터를 보여주기 위한 뷰
name : 데이터를 전달받아서 저장할 객체
viewDidLoad()에서 데이터를 전달 받을 경우의 동작을 작성한다.
name 객체에 값이 있을 경우 nameLabel의 텍스트를 갱신하고, 사이즈를 조정한다.
이동하기 전의 뷰 컨트롤러에서 전달할 name 값을 지정하면 View Controller 전환 시 데이터가 전달된다.
여기서 중요한 점은 다운 캐스팅을 통해서 이동한 뷰 컨트롤러를 지정해주어야 name 객체에 접근할 수 있다.
@IBAction func tabCodePushButton(_ sender: UIButton) {
// 스토리 보드에 있는 뷰 컨트롤러를 인스턴스화 해주어야 함
// 옵셔널로 반환하기 때문에 Guard 문으로 처리
guard let viewController = self.storyboard?
.instantiateViewController(withIdentifier: "CodePushViewController")
as? CodePushViewController // 다운 캐스팅
else {
return
}
viewController.name = "Jinwoo"
// navigationController 의 push View Controller를 호출해서 뷰를 연결
self.navigationController?.pushViewController(viewController, animated: true)
}
다운 캐스팅을 통해 생성한 viewController 객체를 통해서 name을 지정한다.
반드시 view Controller를 변환하는 pushViewController 이전에 코드를 실행해야 정상적인 값을 전달한다.
앱을 테스팅 해보면, 뷰 컨트롤러 전환시 name에 값이 지정된 것을 확인할 수 있다.
이제 이전 뷰 컨트롤러로 돌아갈 시 데이터를 전달하는 방법을 알아야 한다.
Code를 통해서 다음 뷰 컨트롤러로 이동 후 다시 돌아갈 시 protocol과 delegate를 사용해야 한다.
protocol SendDataDelegate : AnyObject{
func sendData(name : String)
}
CodePresentViewController에 SendDataDelegate 프로토콜을 선언한 후 ,
senData 함수를 생성한다.
현재 컨트롤러에서 delegate 변수를 통해서 데이터를 지정하면, 돌아갈 뷰 컨트롤러에서
send data delegate 프로토콜을 채택하여 데이터를 전달 받을 수 있다.
delegate 변수를 선언한 후,
// delegate 변수 앞에는 반드시 weak 키워드를 붙여야 함
// 메모리 누수 발생 가능성 방지
weak var delegate : SendDataDelegate?
뷰 컨트롤러를 전환하는 동작에 선언한 프로토콜을 사용한다.
@IBAction func tabBackButton(_ sender: UIButton) {
// 데이터를 전달 받은 뷰 컨트롤러에서 sendData delegate 프로토콜을 채택
// 델리게이트를 위임 받아서 senData delegate 프로토콜을 생성한 이전 화면 뷰
// 컨트롤러에서 sendData 함수가 실행 됨
self.delegate?.sendData(name: "Jinwoo ")
self.presentingViewController?
.dismiss(animated: true, completion: nil)
}
다시 main view controller로 돌아와서 delegate를 위임받는 코드를 화면 전환 코드 이전에 작성한다.
@IBAction func tabCodePresentButton(_ sender: UIButton) {
// 마찬가지로 스토리 보드에 있는 뷰 컨트롤러를 인스턴스화
guard let viewController = self.storyboard?
.instantiateViewController(withIdentifier: "CodePresentViewController")
as? CodePresentViewController // 다운 캐스팅
else{
return
}
// 풀 스크린으로 변환 -> present 이전에 실행해야 함
viewController.modalPresentationStyle = .fullScreen
viewController.name = "Jinwoo"
// present 메서드에 인스턴스한 Controller를 전달
viewController.delegate = self // 델리게이트 위임 받기 , 프로토콜을 채택해야 함
self.present(viewController, animated: true, completion: nil)
}
위임을 받았으므로 이전 뷰 컨트롤러에서 돌아올 때 원하는 동작을 sendData함수를 통해서 사용할 수 있다.
// 위임 받았기 때문에 함수 사용 가능
func sendData(name: String) {
self.nameLabel.text = name
self.nameLabel.sizeToFit()
}
이제 뷰 컨트롤러 전환 시 성공적으로 데이터를 전달하고, 다시 돌아올 경우 데이터를 전달받을 수 있다.
뷰 컨트롤러 전환 시 위임 프로토콜을 통해서 main view controller의 데이터가 변경 된 것을 확인할 수 있다.
Segue로 전환한 뷰 컨트롤러에서 데이터 전달하기
segue로 화면을 전환할 때 데이터를 전달하는 가장 좋은 방법은 전처리 prepare 메서드이다.
prepare 메서드는 오버라이드 하면 세그웨이를 실행하기 직전에 시스템에 의해서 자동으로 호출된다.
main view Controller에서 prepare 메서드를 오버라이드 한다.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// 세그웨어 실행 이전에 프리페어 메서드가 자동으로 실행 됨
// 전환하려는 뷰 컨트롤러 인스턴스를 가져와야 함
// 다운 캐스팅하여 segue.destination 사용
if let viewController = segue.destination as? SuguePushViewController{
viewController.name = "Jinwoo"
}
}
해당 메서드는 세그웨어 실행 이전에 자동으로 실행되며,
전환하려는 뷰 컨트롤러 인스턴스를 통해서 데이터에 접근할 수 있다.
데이터 접근을 위해서 반드시 다운캐스팅 해야한다.
전환 뷰 컨트롤러에서는 마찬가지로 nameLabel을 선언하고 전달 받은 데이터를 저장한다.
@IBOutlet weak var nameLabel: UILabel!
var name : String?
override func viewDidLoad() {
super.viewDidLoad()
if let name = name {
self.nameLabel.text = name
self.nameLabel.sizeToFit()
}
}
Sugue로 Push 동작 시 성공적으로 데이터가 전달 된 것을 확인할 수 있다.
Sugue에서 이전 뷰 컨트롤러로 데이터를 전달하려면 Code 전환처럼 위임 프로토콜을 사용하면 된다.