라티의 작은 일기장

[21일차] [LED 전광판 앱] 화면간 데이터 전달하기 본문

Swift

[21일차] [LED 전광판 앱] 화면간 데이터 전달하기

코드라티 2023. 3. 12. 23:51

오늘은 화면(View) 간에 데이터를 전달하는 방법에 대해 알아보자.

이전 화면에서 생성된 데이터를 다음 화면에서 활용하는 경우가 분명 생길텐데, 이번 파트에서 잘 학습해두자.

 

이번 실습은 지난번에 화면 전환 구현 예제에서 약간의 코드 변형을 통해 이루어진다.

우선 코드를 활용하여 화면 전환하는 VC의 스토리보드 상에 Label을 추가해주자.

Push / Present 방식에 모두 Label을 추가하였다.

그리고 각 VC의 코드에 해당 Label에 대한 Outlet 변수도 추가해주자.

그리고 그 Outlet 변수 밑에 name이라는 String 프로퍼티도 추가해주자.

var name: String?

 

다음으로 Root View Controller의 코드에서, VC를 인스턴스화 해주는 메소드에 전환되는 VC 클래스로 다운캐스팅하는 코드를 추가해보자.

    @IBAction func tapCodePushButton(_ sender: Any) {
        guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "CodePushViewController") as? CodePushViewController else { return }
        self.navigationController?.pushViewController(viewController, animated: true)
    }
    @IBAction func tapCodePresentButton(_ sender: Any) {
        guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "CodePresentViewController") as? CodePresentViewController else { return }
        self.present(viewController, animated: true, completion: nil)
    }

이렇게 각 타입에 맞는 VC로 다운캐스팅해주면, Root View Controller에서 전환될 두 VC에 정의한 name 프로퍼티에 접근할 수 있게 된다. 위 tapCodePushButton, tapCodePresentButton 메소드에서 간단하게 접근할 수 있는 것이다.

viewcontroller.name = "Rati"

Root View Controller 쪽에서 넘겼으니, 이제 값을 받으러 가보자.

두 VC의 viewDidLoad() 메소드의 코드를 다음과 같이 수정하면 된다.

override func viewDidLoad() {
        super.viewDidLoad()
        if let name = name {
            self.nameLabel.text = name
        }
    }

결과를 확인해보면...

CodePushVC도 잘 나오고

 

CodePresentVC도 잘 나오는 것을 확인할 수 있다.

 

자, 그럼 반대로도 해보자.

전환된 화면에서 그 이전 화면으로 데이터를 넘기는 상황도 충분히 있을 수 있지 않은가?

 

사용할 수 있는 다양한 방법들이 있지만, 제일 자주 사용되는 방식은 delegate(:위임하다) 방식이라고 한다.

해당 방식을 사용해보자.

 

메인 스토리보드로 돌아가서 Root VC 하단에 Label을 하나 추가하였다.

그리고 Root VC에 똑같이 nameLabel이라는 Outlet 변수를 선언해주자.

 

그 다음으로 CodePresentVC에서 Root VC의 nameLabel에 접근하기 위한 사전 작업으로, 프로토콜을 하나 추가해주어야 한다.

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

의미 그대로 String 타입의 데이터를 보내기 위한 프로토콜이다.

그리고 delegate 변수를 클래스 내에 선언해주자.

weak var delegate: SendDataDelegate?

일반 타입이 아니라 weak 키워드를 추가하여 선언해줘야한다. 그렇지 않으면 반환순환참조로 인한 메모리 누수가 발생할 수 있다고 한다.

마지막으로 tapBackButton 메소드에 다음 코드를 추가해보자.

self.delegate?.sendData(name: "Hello, Rati!")

이 코드를 추가하게 되면, CodePresent VC에서 sendData 메소드의 파라미터로 해당 문자열을 넘겼을 때, 이 SendDelegate 프로토콜을 채택하고 delegate를 위임받게 되는 Root VC에서 sendData 메소드가 실행되어 문자열을 받을 수 있게 되는 것이다.

 

delegate를 위임받는 과정은 다음과 같다.

우선 위임받는 코드는 다른 화면을 호출하는 present 메소드 호출 시점의 이전이어야 한다.

하지만 그냥 위임받으면 해당 프로토콜을 채택하라는 에러를 만날 수 있기 때문에, 프로토콜을 먼저 채택해주고,

해당 프로토콜을 준수하기 위한 sendData 메소드도 구현해준다.

    func sendData(name: String) {
        self.nameLabel.text = name
        self.nameLabel.sizeToFit() // 문자열의 길이에 맞춰 Label 사이즈 조정
    }

이제 결과를 확인해보자.

Root VC로 데이터가 잘 전달되는 것을 확인할 수 있다!

 

 

패스트캠퍼스 바로가기 : http://bit.ly/3Y34pE0

 

패스트캠퍼스 [직장인 실무교육]

프로그래밍, 영상편집, UX/UI, 마케팅, 데이터 분석, 엑셀강의, The RED, 국비지원, 기업교육, 서비스 제공.

fastcampus.co.kr

> 본 포스팅은 패스트캠퍼스 환급 챌린지 참여를 위해 작성되었습니다.