iOS/Swift실전

[Swift/iOS프로그래밍] 뷰와 뷰 사이 데이터 전달

Sweetft 2022. 5. 25. 18:37

 

지난 화면전환 네비게이션 글에서 실습한 프로젝트 이후 부분이니 참고바람

https://yejprogramming.tistory.com/62

 

[swift/iOS프로그래밍] navigation controller 4가지 방법, 세그 vs 코드,push vs present

스위프트로 화면전환을 구현하는 방식 중에 네비게이션 컨트롤러가 있다. 세그로 구현하는 것과 코드로 구현하는 것이 있는데 이 중에서도 푸쉬와 프레젠트라는 방식이 있다. 오늘은 이런 4가

yejprogramming.tistory.com

 

 

▼실습 완료 화면

 

코드로 구현한 네비게이션 컨트롤러 부분에서

Push 부분은 첫번째 뷰컨트롤러(루트컨트롤러)에서 두번째 컨트롤러로 데이터 전달,

Present 부분은 delegate으로 두번째 뷰컨트롤러에서 첫번째 컨트롤러로 데이터 전달을 구현했다

 

Segue로 네비게이션 화면전환을 한 경우는 SeguePushViewController에서 첫번째 뷰컨트롤러에서 두번째 뷰컨트롤러로 데이터 전달이 이루어진다.

 

 

데이터 전달 부분의 코드는 각 문장 마다 주석을 상세하게 달아두었으니 참고 바람!

 

 

 

ViewController.swift

import UIKit

class ViewController: UIViewController, SendDataDelegate { // CodePresentViewController에 있는 sendDataDelegate 채택

    @IBOutlet weak var nameLb: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
       
    }

    //첫번째 뷰에서 두번째 뷰로 데이터 넘겨주기
    @IBAction func codePushBtn(_ sender: UIButton) {
        guard let viewController = self.storyboard?.instantiateViewController(identifier:"codePushViewController") as? CodePushViewController else { return } //이렇게 뷰컨트롤러로 다운캐스팅하면 CodePushViewController에 있는 프로퍼티들에 접근 가능함
        viewController.name = "YejProgramming" //다운캐스팅을 했기 때문에 이렇게 codePushViewController에 있는 name 변수에 값을 지정할 수 있음. 아무튼, ViewController에서 name 변수에 저장된 YejProgramming이라는 단어는 실행시 두번째 뷰인 CodePushViewController에서 확인 가능함
        self.navigationController?.pushViewController(viewController, animated: true)
    }
    
    //두번째 뷰에서 첫번째 뷰로 데이터 넘겨주기
    @IBAction func codePresentBtn(_ sender: UIButton) {
        guard let viewController = self.storyboard?.instantiateViewController(identifier: "codePresentViewController") as? CodePresentViewController else { return } //여기서 CodePresentViewController을 다운캐스팅해줌으로써 delegate을 위임받을 수 있음
        viewController.modalPresentationStyle = .fullScreen        
        viewController.delegate = self //delegate 위임
        self.present(viewController, animated: true, completion: nil)
        
    }
    
    //세그웨이를 실행하기 직전에 시스템에 의해 오버라이드된 prepare 메서드가 자동으로 호출됨
    //이 prepare메서드 안에 전환하려는 뷰컨트롤러의 인스턴스를 가져오자
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //segue.destination propertyd을 이용해 전환하려는 뷰 컨트럴로의 인스턴스를 가져올 수 있음
        if let viewController = segue.destination as? SeguePushViewController {
            viewController.name = "YejProgrammingSegue"
        }
    }
    
    //프로토콜 준수
    func sendData(name: String) {
        self.nameLb.text = name //여기서 name은 CodePresentViewController에서 정의한 "YejProgramming 이전 뷰로 데이터 넘겨주기 실습"이다.
        self.nameLb.sizeToFit()
    }
    
}

 

CodePushViewController.swfit

import UIKit

class CodePushViewController: UIViewController {

    @IBOutlet weak var nameLb: UILabel!
    var name: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if let name = name {
            //optional binding
            self.nameLb.text = name //여기서 name은 앞에 viewController에서 지정한 "YejPromming"임
            self.nameLb.sizeToFit() //라벨 길이가 텍스트 길이에 맞도록 조절
        }
        
    }

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

 

CodePresentViewController.swift

mport UIKit

protocol SendDataDelegate: AnyObject {
    func sendData(name: String) //name이라는 파라미터를 넘김
}

class CodePresentViewController: UIViewController {


    weak var delegate: SendDataDelegate? //delegate 패턴을 사용할 때 변수 앞에 weak를 붙여야 함. 메모리 누수 발생할 수 있기 때문. 이렇게 delegate 변수 선언이 완료되면 위임할 준비가 완료됨
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func backBtn(_ sender: UIButton) {
        self.delegate?.sendData(name: "YejProgramming 이전 뷰로 데이터 넘겨주기 실습") //데이터를 전달받은 뷰컨트롤러에서 sendData delegate protocol을 채택하고 delegate을 위임받을 수 있음
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }
    
}

 

SeguePushViewController.swift

import UIKit

class SeguePushViewController: UIViewController {
    @IBOutlet weak var nameLb: UILabel!
    var name: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if let name = name {
            self.nameLb.text = name //여기서 named은 ViewController에서 정의한 YejProgrammingSegue
            self.nameLb.sizeToFit()
        }
    }
    
    @IBAction func backBtn(_ sender: UIButton) {
        //백 버튼 클릭 시 이전화면 이동
        self.navigationController?.popViewController(animated: true)
        //백 버튼 클릭 시 처음화면(루트 뷰) 이동
        self.navigationController?.popToRootViewController(animated: true)
    }
}