ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 화면간 데이터 전달 방법
    iOS/iOS개념정리 2022. 3. 31. 22:59

    화면간 데이터 전달 방법 2가지

    1. ViewController 인스턴스화, 다운캐스팅을 통한 프로퍼티 접근
    2. delegate 패턴. 이것도 인스턴스화, 다운캐스팅이 필요하지만 화면 전환 후 다시 돌아오는 화면에 데이터 전달 가능

     

     

    1. RootView Controller에서 작성한 label text를  버튼 클릭 > 두번째 화면으로  전달 : 다운캐스팅

    - view controller를 전환되려는 화면의 view controller 클래스로  다운캐스팅

    - 다른 화면으로 push/present 되기 전에 label text값을 넘겨주면 값이 전달됨

     

     

    2.  이전 버튼 클릭시 label text 전달 : delegate

    두번째 화면인 codePush viewController에서 이전화면인 view controller로 데이터 전달

    - protocol 정의 

    - delegate로 지정  -> 프로토콜을 채택

     

     

    < 스토리보드에서 segue로 화면 전환 시>

    1. prepare메소드 오버라이딩

    - 세그웨이를 실행하기 전 시스템에 의해 오버라이드 된 메소드가 자동 호출

     

     

    이 외에도 방법은 많음. 각자 편한방법을 선택

     


    전환할 화면에 데이터 전달 (Down Casting)

    1. 데이터를 전달 받을 라벨 아울렛 변수 추가


    2. 데이터를 저장할 변수 추가

    @IBOutlet weak var nameLabel: UILabel!	// 아울렛 변수
    var name: String?	// 데이터를 전달받아 저장할 변수

    3. View Controller 에서 코드 작성

    • ViewController 인스턴스화 메서드에, 전환되는 화면의 ViewController Class 타입으로 다운 캐스팅

    ViewController.swift 의 코드

    @IBAction func tapCodePushButton(_ sender: UIButton) {
      // 가고 싶은 뷰를 인스턴스화, 다운 캐스팅
      guard let viewController = self.storyboard?.
      instantiateViewController(withIdentifier: "CodePushViewController)
      as? CodePushViewController else {return}
      
      // name 프로퍼티에 값 전달하기
      viewController.name = "Kim Sang Woo 1"
      
      // push 로 화면 전환
      self.navigationController?.
      pushViewController(viewController, animated: true)

    이렇게 다운캐스팅 하면 그 ViewController 의 프로퍼티에 접근할 수 있게 된다.


    4. 전환된 화면에서 데이터를 라벨에 띄워보기

    override func viewDidLoad(){
      super.viewDidLoad()
      guard let name = name else {return}
      self.nameLabel.text = name
      self.nameLabel.sizeToFit()
    }

    전환된 화면에서 이전 화면에 데이터 전달 (delegate)

    ref : https://shark-sea.kr/entry/swift-delegate패턴-알아보기


    delegate 패턴

    1. Root ViewController 에 데이터를 받을 라벨 추가


    2. CodePresentViewController.swift 에 delgate 관련 코드 작성

    2-1. 먼저 AnyObject 나 class 를 상속받는 protocol 선언.
    위임 받을 때 어떤 기능을 할 것인지 메뉴얼 정의 같은 개념.

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

    AnyObject 나 class 를 상속하는 프로토콜은, 이 프로토콜은 "오직 클래스에서만 사용이 가능"하다는 것을 의미한다.

    2-2. 타입이 protocol 인 delegate property 를 선언

    weak var delegate: SendDataDelegate?

    weak 을 붙여주지 않는다면 ViewController <-> CodePresentViewController 가 서로를 양방향 참조하기 때문에 ARC 방식인 swift 에서는 메모리가 영원히 해제되지 않게 된다.

    메모리 누수 방지를 위해서 weak 을 붙여주는 것이 좋다. 무작정 weak 을 쓸 수 있는 것은 아니고 클래스에서만 사용가능한 프로토콜에서 사용한다.


    2-3. delegate 에서 사용할 기능 전달

    @IBAction func tapBackButton(_ sender: UIButton){
      // 기능 전달
      self.delegate?.sendData(name: "Kim Sang Woo 3")
      self.presentingViewController?.dismiss(animated: true, completion: nil)
    }

    3. ViewController 에서 위임자 설정, protocol 채택

    guard let viewController = self.storyboard?.instantiateViewController(withIdentifier: "CodePresentViewController") as? CodePresentViewController else {return}
      
    viewController.name = "Kim Sang Woo 2"
    viewController.delegate = self

    위 코드는 "CodePresentViewController 의 대리자는 나(self)야." 라는 의미이다.
    대리자는 당연히 해야 할 역할이 명시되어있는, 같은 protocol 을 채택해야한다.

    class ViewController: UIViewController, SendDataDelegate { ... }

    class 초반에 SendDataDelegate 프로토콜을 추가한다.
    그리고 프로토콜을 준수하기 위해 메서드를 정의해준다.

    func sendData(name: String){
      self.nameLabel.text = name
      self.nameLabel.sizeToFit()
    }

    그러면 CodePresentViewController.swift 에서 작성했던 코드 self.delegate?.sendData(name: "Kim Sang Woo 3") 가 적용되어 name 에 "Kim Sang Woo 3" 가 저장된다.


    Segueway 로 구현된 화면 전달 방식에서 데이터 전달하기 (prepare overriding)

    1. SegPushViewController 에 데이터를 받을 라벨 아울렛 변수 추가


    2. ViewController 에 prepare 메서드 오버라이딩

    • Segueway 로 구현된 화면 전환에서, 데이터를 전달하기 위한 가장 좋은 위치는, 전처리 prepare 메서드prepare 메서드를 오버라이드 하면 Segueway 를 실행하기 직전에 시스템에 의해서 자동으로 호출된다.
    override func prepare(for segue: UIStoryboardSegue, sender: Any?)
    {
      if let viewController = segue.destination as? SegPushViewController {
      viewController.name = "Kim Sang Woo 4"
      }
    }

    3. SegPushViewController 에 라벨 띄우기

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

     

    delegate 정의 시 weak 를 붙이는 이유는?

    var delegete: DeliveryDataProtocol? 로 해도 무방

    but 

    first vc -> second vc를,   second vc -> first vc 를 서로 참조하고 있는데 이럴 경우 메모리가 해제되지 않아서

    좀비처럼 영원히 남아있게 됨 (ARC의 한계: 순환참조)

    이게 하나라면 큰 문제가 없을 수 있겠지만, 좀비가 많이 있다면 앱이 죽을 가능성..

     

    but 무작정 weak를 쓸 수 있는게 아니라,

    protocol에서 오직 이 프로토콜은 "클래스에서만 사용이 가능하다" 라는것이 명시가 되어있어야 함

     ==>  protocol에 class 또는 AnyObject를 상속받는다면 

    이 protocol은 오직 class에서만 사용 가능하다 라는 뜻이 됨 

    ** protocol이 class 또는 AnyObject를 상속받지 않는다면 모든 곳에서 채택이 가능합니다. **

     

    요약하면, weak을 붙이는 이유는 메모리누수를 방지하기 위함

     

     

     

     

     

     

     

     

     

    댓글

Designed by Tistory.