안녕하세요! [생각하는 개발자]입니다.
지난 시간 우리는 뷰 컨트롤러의 일생(Lifecycle)을 짚어보며 화면이 켜지고 꺼지는 타이밍을 통제하는 방법을 배웠습니다. 이제 3부의 마지막 퍼즐을 맞출 시간입니다. 바로 화면과 화면 사이에 데이터를 안전하고 깔끔하게 전달하는 방법입니다.
앱을 만들다 보면 1번 화면(로그인)에서 입력한 유저 아이디를 2번 화면(메인 홈)으로 넘겨주거나, 2번 화면(설정)에서 바꾼 옵션을 1번 화면에 반영해야 하는 일이 반드시 생깁니다. iOS UIKit 생태계에서 이를 해결하는 가장 대표적인 3가지 정석 패턴을 완전히 정복해 봅시다.

3.5.1 캔버스 위에 재료 얹기 (데이터 통로 확보)
데이터를 전달하려면 먼저 목적지가 되는 두 번째 뷰 컨트롤러(DetailViewController)에 데이터를 받아낼 저장소(Property)와 통로가 준비되어 있어야 합니다. 코드로 아래와 같이 뼈대를 배치해 둡니다.
import UIKit
// 데이터를 받아 표현할 목적지 화면
class DetailViewController: UIViewController {
// 3.5.2 1단계: 데이터를 받아둘 저장소(Property)
var receivedUserID: String?
@IBOutlet weak var welcomeLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// 메모리에 로드된 후 넘겨받은 데이터 반영
if let userID = receivedUserID {
welcomeLabel.text = "\(userID)님, 환영합니다!"
}
}
}
3.5.2 [단계별 실습] 방향에 따른 데이터 전달 3대 패턴
데이터가 앞으로 가느냐(A ➔ B), 뒤로 오느냐(B ➔ A), 혹은 사방으로 퍼지느냐에 따라 사용하는 무기가 완전히 달라집니다.
1단계: 순방향 전달 – 프로퍼티 직접 주입 (A ➔ B)
가장 단순하고 직관적인 방법입니다. 화면을 전환하여 띄우기 직전, 새로 생성한 목적지 뷰 컨트롤러의 변수에 데이터를 직접 찔러 넣어주는 방식입니다.
실무 구현:
// 1번 화면(Main)에서 2번 화면(Detail)을 띄울 때guard let detailVC = self.storyboard?.instantiateViewController(withIdentifier: "DetailVC") as? DetailViewController else { return }
// 목적지의 프로퍼티에 직접 데이터 주입
detailVC.receivedUserID = "thoughtful_dev"
self.navigationController?.pushViewController(detailVC, animated: true)
적용 타이밍: 메인 화면에서 상세 화면으로 넘어갈 때처럼, 순방향으로 데이터를 넘길 때 99% 이 방식을 씁니다.
2단계: 역방향 전달 – 델리게이트 패턴 (B ➔ A) ★★★
상세 화면(B)에서 일어난 이벤트나 수정한 데이터를 이전 화면(A)으로 거꾸로 돌려주어야 할 때 사용합니다. iOS 개발의 꽃이자, 대리인을 지정하는 Delegate Pattern입니다.
실무 구현:
// B화면(Detail)에서 프로토콜(규약) 정의
protocol DetailDelegate: AnyObject {
func didUpdateProfile(newName: String)
}
class DetailViewController: UIViewController {
weak var delegate: DetailDelegate? // 대리인 임명용 변수
func saveCompleted() {
// A화면(대리인)에게 데이터 전달하며 일 시키기
delegate?.didUpdateProfile(newName: "생각하는 개발자")
self.navigationController?.popViewController(animated: true)
}
}
이제 A화면에서 이 프로토콜을 채택(extension MainVC: DetailDelegate)하고, detailVC.delegate = self로 자처하면 B가 닫힐 때 A의 함수가 트리거되며 데이터를 안전하게 거꾸로 넘겨받을 수 있습니다.
3단계: 다방면 전달 – 노티피케이션 센터 (NotificationCenter)
화면의 앞뒤 관계와 상관없이, 앱 전체에 "이 라디오 방송 들을 사람 다 모여라!" 하고 데이터를 방송(Broadcast)하는 시스템입니다.
실무 구현:
// 방송하기 (Post)
NotificationCenter.default.post(name: Notification.Name("UserLoggedOut"), object: nil, userInfo: ["time": Date()])
// 청취하기 (Observer 등록)
NotificationCenter.default.addObserver(self, selector: #selector(handleLogout), name: Notification.Name("UserLoggedOut"), object: nil)
적용 타이밍: 로그아웃처럼 하나의 이벤트로 인해 전혀 다른 곳에 있는 여러 화면(마이페이지, 홈 탭, 알림창)이 동시에 데이터를 갱신해야 할 때 유용합니다.
👨💻 안드로이드 개발자를 위한 비교 조각
안드로이드에서 화면 간 데이터를 넘길 때 Intent에 putExtra()를 이용해 번들(Bundle)로 데이터를 포장했던 기억이 나실 겁니다. 받을 때도 intent.getStringExtra()처럼 Key 값을 매칭해야 했죠.
iOS UIKit의 순방향 전달은 그런 포장 과정 없이 목적지 클래스의 객체 프로퍼티에 직접 변수 대입하듯(detailVC.userID = ...) 직관적으로 처리합니다. 타입 안정성(Type Safety) 면에서 컴파일러가 강하게 잡아주기 때문에 오타로 인한 런타임 에러가 없다는 것이 iOS 방식의 아주 큰 매력입니다.
반대로 역방향 전달은 안드로이드의 startActivityForResult 인터페이스 구현과 iOS의 Delegate 구조가 철학적으로 완전히 일맥상통합니다.
🎯 오늘의 요약
- 순방향(A➔B) 데이터 전달은 목적지 뷰 컨트롤러의 Property(프로퍼티)에 직접 주입한다.
- 역방향(B➔A) 데이터 전달은 Delegate Pattern(델리게이트)을 활용해 결합도를 낮추고 안전하게 회수한다.
- 1:N 혹은 불특정 다수에게 이벤트를 뿌릴 때는 NotificationCenter 라디오 방송국을 이용한다.
이 3가지 원칙만 손에 익히면 화면이 아무리 많아져도 데이터의 핏줄을 꼬임 없이 완벽하게 연결할 수 있습니다.
이로써 UIKit의 기본 화면 구조를 다루는 3부가 모두 끝났습니다! 다음 장 [iOS 4-1]부터는 코드 세계를 잠시 벗어나, 현업 협업의 핵심이자 주니어들의 통곡의 벽인 iOS 맞춤형 Git 버전 관리와 .gitignore 설정법으로 돌아오겠습니다. 함께 생각하고 성장합시다!