본문 바로가기
iOS/iOS

[iOS] 다른 화면으로 데이터 전달하기

by 원만사 2021. 12. 3.
반응형

 화면간 데이터 전달 방법에는 여러 가지 방법이 있다. 해당 포스팅에서는 프로퍼티에 직접 접근하는 방법, 액션 세그웨이를 이용한 화면 전환에서의 데이터 전달(prepare) 그리고 Delegate를 이용하여 이전 화면에 데이터를 전달하는 방법에 대해서 알아보자.

 

[프로퍼티 직접 접근]

 전달하고자 하는 데이터를 뷰 컨트롤러의 프로퍼티에 직접 접근해서 넘기는 방식이다. 아래 사진에서 Green View Controller에서 Blue View Controller에게 "Blue View Controller로 데이터 이동 완료"라는 String 형식의 데이터를 넘긴다고 생각해보자.

 데이터 전송 버튼을 클릭하면 Blue View Controller로 화면이 전환 되고, 해당 데이터를 Blue View Controller의 Label에 출력 되도록 할 것이다. 이를 위한 코드는 다음과 같다.

 

GreenViewController

@IBAction func clickPushButton(_ sender: UIButton) {
        guard let viewController =
                self.storyboard?.instantiateViewController(withIdentifier: "blueViewController") as? blueViewController
        else { return }
        
        viewController.data = "Blue View Controller로 데이터 이동 완료"
        self.navigationController?.pushViewController(viewController, animated: true)
    }

 

BlueViewController

import UIKit

class blueViewController: UIViewController {

    @IBOutlet weak var dataLabel: UILabel!
    var data: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 전달 받은 데이터를 Label에 표시
        if let data = data {
            dataLabel.text = data
            dataLabel.sizeToFit()
        }
    }

    @IBAction func clickBackButton(_ sender: UIButton) {
        self.navigationController?.popViewController(animated: true)
    }
    
}

 중요한 부분은 뷰 컨트롤러를 인스턴스화 하는 과정에서 해당 뷰 컨트롤러에 연결된 파일로 다운캐스팅 하는 부분이다. 위와 같이 다운캐스팅을 하면 해당 뷰 컨트롤러의 프로퍼티에 직접 접근할 수 있다. 

 

 이 방법은 push, present 방식으로 화면을 전환하는 경우에만 데이터가 정상적으로 넘어간다.

 

[Delegate를 이용하여 이전 화면에 데이터 전달]

 Delegate를 이용하면 데이터를 주고 받는 뷰 컨트롤러가 서로 의존하지 않고 떨어져 있는 구조를 유지하게 된다. Delegate 패턴을 사용하여 현재 화면의 데이터를 이전 화면에 넘겨 주는 것이 가능하다. 

 이번에는 Blue View Controller에서 Green View Controller로 "To green view controller"라는 String 데이터를 넘겨 준다고 가정하자. 이를 위해 먼저 Delegate 프로토콜을 정의해야 한다.

 

BlueViewController

protocol SendDataDelegate: AnyObject {
    func sendData(data: String)
}

 

 Green View Controller에서는 위의 SendDataDelegate 프로토콜을 채택해서 해당 프로토콜을 위한 메서드를 구현해야 한다. 이후 BlueViewController로 이동하기 전에 BluewViewController의 delegate 프로퍼티를 self로 지정한다.

 

GreenViewController

import UIKit

class ViewController: UIViewController, SendDataDelegate {
    @IBOutlet weak var dataLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

    @IBAction func clickPushButton(_ sender: UIButton) {
        guard let viewController =
                self.storyboard?.instantiateViewController(withIdentifier: "blueViewController") as? blueViewController
        else { return }
        
        viewController.data = "Blue View Controller로 데이터 이동 완료"
        
        viewController.delegate = self // delegate를 위임받음
        self.navigationController?.pushViewController(viewController, animated: true)
    }
    
    // SendDataDelegate 프로토콜 구현
    func receiveData(data: String) {
        self.dataLabel.text = data
        self.dataLabel.sizeToFit()
    }
}

 

 Blue View Controller에서는 delegate의 메서드를 실행시켜 "To green view controller"를 전달하도록 한다.

 

BlueViewController

import UIKit

protocol SendDataDelegate: AnyObject {
    func receiveData(data: String)
}

class blueViewController: UIViewController {

    @IBOutlet weak var dataLabel: UILabel!
    var data: String?
    weak var delegate: SendDataDelegate?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let data = data {
            dataLabel.text = data
            dataLabel.sizeToFit()
        }
    }

    @IBAction func clickBackButton(_ sender: UIButton) {
        delegate?.receiveData(data: "To green view controller") // 데이터 전달
        self.navigationController?.popViewController(animated: true)
    }
    
}

 

 

[액션 세그웨이 데이터 전달(prepare)]

 Green View Controller와 Orange View Controller가 세그웨이를 사용하여 연결되어 있다. Orange View Controller로 이동할 때 "hello orange"라는 String 데이터를 보내자. 

 세그웨이를 사용하여 화면을 전환할 때 먼저 prepare(for segue: sender:) 메서드가 실행된다. Green View Controller에서 prepare 메서드를 오버라이드하여 이를 이용하여 데이터를 전달하면된다.

 

Green View Controller

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let viewController = segue.destination as? orangeViewController {
            viewController.data = "hello orange"
        }
    }

 

Orange View Controller

import UIKit

class orangeViewController: UIViewController {
    @IBOutlet weak var dataLabel: UILabel!
    var data: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        if let data = data {
            self.dataLabel.text = data
            self.dataLabel.sizeToFit()
        }
    }

}

 한 가지 주의할 것은 prepare 메서드 안에서 OrangeVC의 Label에 바로 접근하는 것이 아닌 data라는 프로퍼티를 하나 만들어서 GreenVC의 prepare 메서드에서 해당 data 프로퍼티에 값을 저장하고 OrangeVC의 viewDidLoad()가 실행될 때 dataLabel에 값을 넣도록 했다. 이는 prepare 메서드에서 dataLabel에 바로 접근할 수 없기 때문이다. 이유는 다음과 같다.

  • prepare 메서드 내에서 orangeViewController 객체의 인스턴스를 가져오긴 했지만, 아직 뷰의 요소들은 메모리에 올라가 있지 않은 상태이기 때문이다.
  • 즉, 인스턴스에 있는 변수인 data는 있지만, 화면에 보여줄 view의 요소에 해당하는 dataLabel은 아직 생성이 안 된 상태인 것이다.

 

참고

- https://jiyeonlab.tistory.com/9

- https://velog.io/@nnnyeong/iOS-VC-간-데이터-전달-방법

 

 

반응형

댓글