iOS/iOS개념정리

화면간 데이터 전달 방법

soultreemk 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을 붙이는 이유는 메모리누수를 방지하기 위함