관리 메뉴

java,javascript,android,php,sql,공부용,메모용

화면간 데이터 전달 / Xcode SwiftUI 본문

모바일/SwiftUI ios 공부

화면간 데이터 전달 / Xcode SwiftUI

yy_dd2 2021. 12. 2. 23:06
반응형

이전 프로젝트에 이어서 화면간 데이터 전달 확인하기

스토리보드에 코드로 Push와 코드로 Present에 라벨을 하나씩 추가한다

그리고 각 컨트롤러에 내용추가

 

** 버튼을 누르면 이동되는 화면에 라벨이 추가되었고 거기로 내용이 전달될것

CodePushViewController

화면이 로드될때 나타나도록 추가했다

import UIKit

class CodePushViewController: UIViewController {

    @IBOutlet weak var nameLabel: UILabel!
    var name: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 옵셔널바인딩
        if let name = name {
            self.nameLabel.text = name
            // nameLabel 글씨짤림 방지
            self.nameLabel.sizeToFit()
        }
    }
  
    @IBAction func tapBackButton(_ sender: UIButton) {
        self.navigationController?.popViewController(animated: true)
    }
    
}

 

CodePresentViewController

import UIKit

class CodePresentViewController: UIViewController {

    @IBOutlet weak var nameLabel: UILabel!
    var name: String?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if let name = name {
            self.nameLabel.text = name
            // nameLabel 글씨짤림 방지
            self.nameLabel.sizeToFit()
        }
    }

    @IBAction func tapBackButton(_ sender: UIButton) {
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }
}

 

ViewController

    @IBAction func tabCodePushButton(_ sender: UIButton) {
        //스토리보드에 있는 뷰컨트롤러(새로만든 코드로 Push 화면)를 인스턴스화 하기
        // 여기서 매개변수 identifier를 스토리보드에서 설정한 id를 작성한다
        // 옵셔널 반환이기 때문에 guard 문으로 처리한다
        guard
           // let viewController = self.storyboard?.instantiateViewController(identifier: "CodePushViewController")
            // 다운캐스팅 as? 특정 클래스 타입의 상수, 변수 하위 클래스의 인스턴스를 참조할 수 있다.
            
            let viewController = self.storyboard?.instantiateViewController(
            	identifier: "CodePushViewController") 
                	as? CodePushViewController
        else { return }
        viewController.name = "young "
        // 화면전환 코드 여기서 viewController는 위에 사용된 상수명
        self.navigationController?.pushViewController(viewController , animated: true)

    }
    @IBAction func tapCodePresentButton(_ sender: UIButton) {
        guard
            //let viewController = self.storyboard?.instantiateViewController(identifier: "CodePresentViewController")
            let viewController = self.storyboard?.instantiateViewController(
            	identifier: "CodePresentViewController") 
            		as?  CodePresentViewController
        else { return }
        // 모달로 나오는 화면을 풀스크린으로 변경
        viewController.modalPresentationStyle = .fullScreen
        viewController.name = "young"
        self.present(viewController, animated: true, completion: nil)
    }

 

이전이나 Back버튼을 누르면 데이터가 전달되도록 해보기

버튼을 눌러서 온 곳에서 데이터가 전달되도록 했으니 반대로 해보자

버튼이 있는 ViewController에 라벨추가 -Class파일에도 라벨 @IBOutlet을 추가한다

 

import UIKit

// 이전화면으로 데이터 전달
protocol SendDataDelegate: AnyObject {
    func sendData ( name: String)
}

class CodePresentViewController: UIViewController {

    @IBOutlet weak var nameLabel: UILabel!
    var name: String?
    //이전 화면으로 데이터전달
    //weak는 메모리 누수 방지
    weak var delegate : SendDataDelegate?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        if let name = name {
            self.nameLabel.text = name
            // nameLabel 글씨짤림 방지
            self.nameLabel.sizeToFit()
        }
    }

    @IBAction func tapBackButton(_ sender: UIButton) {
        //이전 화면으로 데이터전달
        //dismiss 데이터 호출 전에 해야함
        self.delegate?.sendData(name: "CodePresentViewController에서 이전화면으로 보내는 데이터")
        // 이전화면 컨트롤러에서 델리게이트 위임 받아야함
        
        self.presentingViewController?.dismiss(animated: true, completion: nil)
    }
}

 

Back버튼을 누르면 데이터가 전달되도록 해야한다

프로토콜을 만들어서 데이터가 전달될 수 있도록 만들어주자

https://tog-code.tistory.com/98

프로토콜을 다시 확인해야했다. 프로토콜은 프로퍼티,메서드,이니셜라이저를 사용할 수 있고 겟터셋터를 만들어서 주고 받는 역활을 한다

// 이전화면으로 데이터 전달
protocol SendDataDelegate: AnyObject {
    func sendData ( name: String)
}

이전화면으로 전달할 프로토콜 메서드를 만들었다.

여기서 :AnyObject는 스위프트의 모든 타입을 지칭하는 키워드 모든 타입을 할당하여 비교가 가능하다. (하나가 Any면 다른 타입과 비교가능)

 

프로토콜 변수 선언

    //이전 화면으로 데이터전달
    //weak는 메모리 누수 방지
    weak var delegate : SendDataDelegate?

 

 

Back 버튼을 누르면 이전화면으로 갈때 데이터를 전달할 수 있게

       self.delegate?.sendData(name: "CodePresentViewController에서 이전화면으로 보내는 데이터")

 

 

ViewController(버튼이 있는곳)에서

이화면에 오면 받을 데이터를 작성한다

    @IBAction func tapCodePresentButton(_ sender: UIButton) {
        guard
            //let viewController = self.storyboard?.instantiateViewController(identifier: "CodePresentViewController")
            let viewController = self.storyboard?.instantiateViewController(identifier: "CodePresentViewController") as?  CodePresentViewController
        else { return }
        // 모달로 나오는 화면을 풀스크린으로 변경
        viewController.modalPresentationStyle = .fullScreen
        viewController.name = "young"
        
        // 이전화면으로 올때 받는 데이터
        viewController.delegate = self          
        // 맨위에 클래스 옆에 SendDataDelegate 프로토콜 채택하라고함 Cannot assign value of type 'ViewController' to type 'SendDataDelegate?'
        
        self.present(viewController, animated: true, completion: nil)
    }

viewController.delegate = self를 하면 오류나는데 프로토콜을 채택하지 않아서다

import UIKit

class ViewController: UIViewController, SendDataDelegate {

맨위로가서 ,SendDataDelegate를 작성해서 채택해주자

 

그리고 데이터를 받았으면 받은 데이터를 Label에 표시되도록 해야한다.

    // 채택한 프로토콜의 sendData 메서드 정의
    func sendData(name: String) {
        //nameLabeldp 표시되도록함
        self.nameLabel.text = name
        // nameLabel 글씨짤림 방지
        self.nameLabel.sizeToFit()
    }

 


 

Storyboard에서 데이터를 전달하기 ViewController 에서 직접 작성해서 전달

 

SuguePushViewController 화면에 라벨을 추가하고 코드창에 아래내용을 추가 (스토리보드에서 라벨 우클릭해서 @IBOutlet 가져옴)

import UIKit

class SuguePushViewController: UIViewController {

    @IBOutlet weak var nameLabel: UILabel!
    var name: String?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("SuguePuchViewController 뷰가 로드 되었다")
    }

 

스토리보드에 추가된 데이터를 전달할때 좋은건 prepare 메서드라고 한다

ViewController에서 코드를 추가한다

    // 세그웨이 실행 전에 자동으로 호출된다
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // 전환하려는 뷰컨트롤러 인스턴스 가져오기
        // segue.destination
        // 다운캐스팅 (세그푸시뷰컨트롤러로)
        if let viewController = segue.destination as? SuguePushViewController {
            viewController.name = "SuguePushViewController"
        }
    }

 

그리고 다시 SuguePushViewController로가서 name 프로퍼티에 값을 받게 작성해주자

import UIKit

class SuguePushViewController: UIViewController {

    @IBOutlet weak var nameLabel: UILabel!
    var name: String?
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        print("SuguePuchViewController 뷰가 로드 되었다")
        if let name = name {
            self.nameLabel.text = name
            self.nameLabel.sizeToFit()
        }
    }

 


1. ViewController 인스턴스화, 다운캐스팅을 통한 프로퍼티 접근

(스토리보드에서 직접 연결한 화면간의 데이터 전달)

2. delegate 패턴. 이것도 인스턴스화, 다운캐스팅이 필요하지만 화면 전환 후 다시 돌아오는 화면에 데이터 전달 가능

(코드로 데이터를 넘겨주고 받는다)

1번 방법은 그냥 일방적으로 다음 화면에 데이터를 넘겨준다면,
delegate 패턴은 B 화면에서 class 용 프로토콜 타입 delegate 를 생성해준 뒤

그 A 화면에서 그걸 delegate 위임 받는 것이므로 상호작용 느낌이 크다.

반응형
Comments