안녕하세요! [생각하는 개발자]입니다.
우리는 지난 시간에 뷰 컨트롤러가 태어나서 사라질 때까지의 타임라인(Lifecycle)을 지배하는 법을 배웠습니다. 이제 5부의 마지막 퍼즐이자, 앱에 유기적인 흐름을 만들어 줄 "화면 간 데이터 전달(Data Transfer)"의 정석을 마스터할 시간입니다.
로그인 화면(A)에서 입력받은 유저 ID를 메인 홈 화면(B)으로 전달하거나, 반대로 프로필 수정창(B)에서 수정한 이메일 주소를 이전 메이페이지(A)로 안전하게 되돌려주어야 하는 상황은 앱 개발에서 매 순간 발생합니다. 상황에 맞춰 데이터의 핏줄을 꼬임 없이 연결해 줄 iOS 3대 데이터 전달 패턴을 완전히 정복해 보겠습니다.

5.3.1 캔버스 위에 재료 얹기 (받는 쪽 화면 설정)
데이터를 건네받을 목적지 화면(DetailViewController)에 데이터를 수용할 저장 공간(Property)을 명확하게 뚫어 놓는 것부터 시작합니다.
import UIKit
// 데이터를 건네받아 출력할 목적지 뷰 컨트롤러
class DetailViewController: UIViewController {
// 5.3.2 1단계: 데이터를 담아둘 프로퍼티 선언
var receivedUserID: String?
@IBOutlet weak var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// 메모리에 뷰가 로드된 후 안전하게 바인딩
if let userID = receivedUserID {
titleLabel.text = "\(userID)님, 반갑습니다!"
}
}
}
5.3.2 [단계별 실습] 흐름의 방향에 따른 3가지 데이터 전달 기법
데이터의 전달 방향이 순방향(앞으로 가기)이냐, 역방향(뒤로 가기)이냐, 혹은 불특정 다수에게 흩뿌리기(사방으로 가기)이냐에 따라 사용하는 도구가 완전히 달라집니다.
1단계: 순방향 데이터 전달 ➔ 프로퍼티 직접 대입 (A ➔ B)
화면이 넘어가는 방향과 데이터의 흐름이 일치하는 가장 기본적이고 직관적인 패턴입니다. 전환할 다음 화면의 인스턴스를 생성한 직후, 외부에서 프로퍼티에 직접 찔러 넣어줍니다.
- 실무 구현:
// 1번 화면(Home)에서 2번 화면(Detail)을 띄우는 시점
guard let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "DetailVC") as? DetailViewController else { return }
// 목적지 객체의 변수에 다이렉트로 값 할당
detailVC.receivedUserID = "thinking_developer"
self.navigationController?.pushViewController(detailVC, animated: true) - 적용 타이밍: 목록 리스트에서 특정 아이템 상세 페이지로 진입할 때 유용합니다.
2단계: 역방향 데이터 전달 ➔ 델리게이트 패턴 (B ➔ A) ★★★
상세 페이지(B)에서 입력한 값이나 선택된 이벤트를 이전 화면(A)으로 거꾸로 돌려주어야 할 때 사용합니다. iOS 아키텍처의 꽃인 Delegate Pattern(위임 패턴)입니다.
"나 대신 이 함수(규약)를 실행할 대리인을 지정해 둔다"는 개념으로 작동합니다.
- 실무 구현:
// 1. 프로토콜(규약/계약서) 정의
protocol ProfileUpdateDelegate: AnyObject {
func didUpdateNickname(_ name: String)
}
// 2. 값을 던져주는 화면 (B)
class DetailViewController: UIViewController {
// 메모리 누수(강한 참조 순환) 방지를 위해 weak 필수 선언
weak var delegate: ProfileUpdateDelegate?
@IBAction func saveButtonTapped(_ sender: UIButton) {
// 대리인(A)에게 나 대신 이 함수를 실행하라고 명령하면서 값 던지기
delegate?.didUpdateNickname("생각하는 개발자")
self.navigationController?.popViewController(animated: true)
}
} - 이후 이전 화면(A)에서 이 프로토콜을 준수(extension MainVC: ProfileUpdateDelegate)하도록 메서드를 구현한 뒤, detailVC.delegate = self로 대리인을 자기 자신으로 선언해주면 안전하게 거꾸로 데이터를 수거할 수 있습니다.
3단계: 1 대 다수(1:N) 데이터 전달 ➔ 노티피케이션 센터 (NotificationCenter)
화면의 상하 관계나 계층 구조가 완전히 깨진 상태에서, 앱 전역에 라디오 방송국처럼 "이 이벤트 발생했으니 귀 기울이고 있던 화면들은 다 갱신해!" 하고 신호를 보냅니다.
- 실무 구현:
// 방송하기 (Post)
NotificationCenter.default.post(name: Notification.Name("UserLogoutSuccess"), object: nil, userInfo: ["timestamp": Date()])
// 청취하기 (Observer 등록 - 수신하고 싶은 화면의 viewDidLoad 등에서 등록)
NotificationCenter.default.addObserver(self, selector: #selector(handleLogout), name: Notification.Name("UserLogoutSuccess"), object: nil)
- 적용 타이밍: 로그아웃, 네트워크 연결 끊김, 앱 테마 변경(다크모드 전환)처럼 모든 화면이 동시에 알아차려야 하는 전역 이벤트를 다룰 때 유용합니다.
👨💻 안드로이드 개발자와의 비교 조각
안드로이드에서 화면 간 데이터를 통신할 때 Intent에 Bundle을 포장하여 putExtra()로 넘기고, 되받을 때는 startActivityForResult()와 onActivityResult() 혹은 최신 ActivityResultLauncher를 매칭하느라 고생하셨던 기억이 있으실 겁니다.
iOS UIKit의 순방향 전달은 **타입 안정성(Type Safety)**이 보장된 객체 지향의 본질을 그대로 살려, 컴파일 타임에 멤버 프로퍼티 변수를 직접 찔러 넣어 관리하므로 번들 내부의 "String Key" 오타로 인한 런타임 에러가 원천적으로 예방된다는 장점이 있습니다.
역방향의 델리게이트 또한 안드로이드 진영에서 커스텀 다이얼로그나 프래그먼트 간 이벤트를 주고받을 때 정의하는 Java/Kotlin의 Interface 콜백 구조와 완벽히 동일한 사상을 공유합니다. 역시 뼈대가 튼튼한 개발자라면 어떤 OS든 금방 구조를 꿰뚫어 볼 수 있습니다.
🎯 오늘의 요약
- 순방향(A➔B)은 다음 인스턴스의 Property(프로퍼티)에 직접 주입한다.
- 역방향(B➔A)은 강한 참조 순환을 차단한 Delegate(위임) 패턴을 활용해 단단하고 느슨하게 엮는다.
- 불특정 다수(1:N)에게 공통 이벤트를 송출해야 할 때는 NotificationCenter 시스템을 동원한다.
화면 전환(5-1)과 라이프사이클(5-2)에 이어 데이터의 핏줄(5-3)까지 완벽하게 이어붙임으로써, 비로소 살아 움직이는 모바일 앱의 흐름 제어권을 손에 쥐게 되었습니다. 5부를 아주 훌륭하게 클리어하셨습니다!
다음 장 [iOS 6-1]부터는 리스트 형태의 거대한 다이내믹 UI를 표현하기 위한 관문이자, 오토레이아웃의 숨겨진 보스인 스크롤 뷰(UIScrollView)의 원리와 오토레이아웃 배치 공식을 격파해 보겠습니다. 생각하는 힘을 기르며 다음 조각으로 무브해 봅시다!