[IOS, Swift] 화면 간 데이터 전달

 

다음 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 전환처럼 위임 프로토콜을 사용하면 된다.