UIKit
- iOS 앱의 사용자 인터페이스(UI)를 만들고 관리할 수 있게 해주는 애플의 공식 프레임워크
- "버튼, 텍스트, 화면 전환, 터치 이벤트" 등을 다루는 도구상자!
- UIView를 통해 화면을 구성하고, UIViewController를 통해 화면을 관리
앱의 실행과정
1. 🧾 @main: 앱의 시작점
@main
class AppDelegate: UIResponder, UIApplicationDelegate {...}
- Swift에서 프로그램의 시작은 보통
main() 함수
- iOS 앱에서는 이걸 대체하는 게 바로
@main
- Swift가 이 클래스를 앱의 진짜 시작점(main entry point)으로 인식
- 내부적으로는
UIApplicationMain() 함수가 자동 호출됨
2. 🚪 UIApplicationMain(): 앱의 진입문
- iOS 앱이 처음 실행될 때 자동으로 호출되는 핵심 함수
- 내부적으로 iOS는 앱을 실행할 때
UIApplicationMain(_:_:_:_:)을 호출하여 UIKit 앱을 시작함
- 주요 역할
- 앱 프로세스 초기화
UIApplication 객체 생성
AppDelegate 객체 생성 및 연결
- Main Run Loop 시작 → 이벤트 처리 준비 완료
3. 🏃♂️ UIApplication과 AppDelegate
UIApplication: 앱 전체를 대표하는 객체 (모든 앱에 딱 하나)
AppDelegate:
- 앱 실행, 백그라운드 진입, 종료 등
- 앱의 상태 변화에 대응하는 콜백을 받는 객체
4. 🔄 Main Run Loop (메인 런 루프)
- 앱이 꺼질 때까지 계속 돌고 도는 이벤트 처리 루프
- 사용자 입력(터치, 제스처), 타이머, 네트워크 응답, 화면 그리기 등을 순차적으로 처리하고, 화면을 업데이트할 시점을 조율함
- 예: 🌀 계속 도는 커다란 회전목마- 사용자의 손짓(터치), 알람(타이머), 메시지(알림) 등을 한 칸씩 태워서 처리함.
💡 앱 실행 순서 요약
1. 사용자가 앱 아이콘 탭
2. @main 붙은 클래스 탐색
3. 내부에서 UIApplicationMain() 실행
4. UIApplication 객체 생성
5. AppDelegate 생성 및 앱 상태 콜백 연결
6. Main Run Loop 시작
7. 사용자 이벤트 처리, UI 업데이트 시작
📌 정리
| 구성 요소 | 설명 |
|---|
@main | Swift에서 앱의 시작점을 지정 |
UIApplicationMain() | UIKit 앱 전체 실행 흐름 시작 |
UIApplication | 앱을 총괄하는 객체 |
AppDelegate | 앱 상태 변화에 대응하는 콜백 처리 |
Main Run Loop | 사용자 이벤트와 UI 갱신을 계속해서 처리하는 메인 루프 |
Scene과 Window
1. UIKit의 구조 변화
- iOS 12 이전
- 앱에 하나의 화면만 존재 (멀티 윈도우 없음)
AppDelegate가 모든 앱 생명주기와 화면 초기화 담당
- iOS 13부터
- iPad나 Mac에서 멀티 윈도우를 지원하려면 화면 단위로 따로 관리할 수 있는 시스템이 필요
AppDelegate: 앱 전체 담당
SceneDelegate: 각 화면(창)마다 생명주기 관리
| 항목 | AppDelegate | SceneDelegate |
|---|
| 역할 | 앱 전체의 생명 주기 관리 | 개별 Scene(화면)의 생명 주기 관리 |
| 호출 시점 | 앱 전체 실행/종료 시 | Scene 생성/전환 시 |
| 예시 메서드 | didFinishLaunching, applicationDidEnterBackground | sceneDidBecomeActive, sceneWillResignActive |
1. UIScene (하나의 윈도우 화면)
- 앱 내 하나의 독립적인 UI 환경
- 앱 UI의 각 인스턴스를 관리(windows, viewControllers)
- 하나의 앱은 여러 Scene과 SceneDelegate 객체를 동시에 활성화 가능
2. UIWindowScene
UIScene의 하위 클래스
- 하나 이상의 window를 관리함
- 윈도우에 연결된 Scene → 실제 UI를 표현하는 데 사용
3. SceneDelegate
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
}
func sceneDidBecomeActive(_ scene: UIScene) {...}
func sceneWillResignActive(_ scene: UIScene) {...}
}
- 하나의 Scene에 대한 생명주기 관리 담당
- 각각의 Scene마다 별도로 SceneDelegate가 붙고 사용자의 창 조작(스플릿, 스위치 등)에 따라 독립적으로 작동
4. UISceneSession
- Scene에 대한 정보(configuration)를 갖고 있는 객체
- Scene의 인스턴스를 추적
- 사용자의 창 하나하나에 대해 하나씩 존재
- Scene을 복원하거나 상태를 저장할 때 사용됨
💡 실행 흐름
@main → UIApplicationMain()
→ AppDelegate
↳ SceneSession 생성됨
↳ SceneDelegate 생성됨
↳ UIWindow + UI 생성됨
📌 정리
| 용어 | 역할 |
|---|
UIScene | 하나의 "장면" (앱의 한 화면 또는 윈도우) |
UIWindowScene | 화면(윈도우) 관련 설정이 포함된 Scene |
UISceneSession | 하나의 Scene을 추적하고 복원할 수 있는 객체 |
SceneDelegate | 각 Scene의 생명주기를 관리하는 클래스 |
AppDelegate | 앱 전체의 생명주기를 관리하는 클래스 |
Life Cycle
1. App Life Cycle (앱 전체 생명주기)
| 상태 | 설명 |
|---|
| Not Running | 실행되지 않았거나, 종료된 상태 |
| Inactive | 실행중이지만, 이벤트를 받지 않는 상태. 잠깐 비활성 상태 (ex: 전화 왔을 때) |
| Active | 앱이 실질적으로 활동중인 상태 |
| Background | 백그라운드(홈버튼)로 넘어간 상태 (ex: 음악 듣기) |
| Suspended | 빠른 재실행을 위해 메모리에 남아 있지만 활동을 멈춘 상태. 메모리 부족 시 강제종료 |
2. UIViewController Life Cycle (화면 하나의 생명주기)
| 메서드 | 설명 |
|---|
| loadView | self.view를 만들 때 호출(특별한 상황 이외엔 오버라이드 X) |
| viewDidLoad | View가 메모리에 로드된 후 호출. 처음 한 번만 실행 |
| viewWillAppear | View가 나타나기 직전에 매번 호출 |
| viewDidAppear | View가 나타난 직후 호출. 화면에 적용될 애니메이션을 동작함 |
| viewWillDisappear | View가 사라지기 직전 호출 |
| viewDidDisappear | View가 제거된 직후 호출 |
📌 정리
| 항목 | App Life Cycle | UIViewController Life Cycle |
|---|
| 비유 | 하나의 "극장 전체"를 여닫는 흐름 (개장, 중단, 폐장) | 극장 안에서 상영되는 "한 편의 영화"의 흐름 (시작, 상영, 종료) |
| 대상 | 앱 전체 (실행, 중단, 종료 등) | 화면 하나 (로딩, 보임, 사라짐, 해제 등) |
| 위치 | AppDelegate, SceneDelegate | UIViewController 서브클래스 |
| 사용 목적 | 앱 상태에 따라 데이터 저장, 정리, 네트워크 중단 등 | 화면 준비, 데이터 로딩, UI 설정 등 |
| 콜백 횟수 | 앱 실행 상태에 따라 한두 번 | 뷰 전환마다 여러 번 반복 |
UIResponder Chain과 이벤트
1. UIResponder
- 이벤트(터치, 제스처, 키보드 등)에 반응하고 관리하는 객체
- UIKit의 많은 객체들(
UIView, UIViewController 등)이 상속받음
- 이벤트를 처리하거나 다른 Responder로 넘기거나 둘 중 하나의 동작을 반드시 진행함
2. Hit-Testing: 누가 이벤트를 받을지 결정하는 과정
- 사용자 손가락이 화면을 터치했을 때 가장 안쪽에 있는 view부터 검사해서 이벤트를 누가 받을지 First Responder를 결정
💡 동작 순서
1. touchesBegan 등의 터치 이벤트 발생
2. 시스템이 루트 뷰부터 hitTest(_:with:) 호출
3. 가장 안쪽에 위치한 뷰를 찾음 (isUserInteractionEnabled가 true여야 함. false일 경우 무시됨)
4. 찾은 뷰가 First Responder가 될 자격 있음
3. First Responder
- 현재 이벤트를 받고 있는 객체
- 예: 텍스트 필드에 커서가 깜빡이면, 그
UITextField가 First Responder
4. Responder Chain: 이벤트가 전달되는 흐름
- 이벤트가 발생했을 때, 처리할 대상이 없으면 다음 대상으로 넘기는 시스템
- UIKit에서 터치, 키보드 입력 등 모든 사용자 입력 이벤트는 Responder Chain을 따라 전달됨
💡 이벤트 처리 흐름
1. Hit Testing: 가장 안쪽의 터치된 뷰 결정
2. 이벤트 전달: 터치된 뷰가 이벤트 처리 시도
3. 실패하면?: 다음 Responder에게 전달 (Responder Chain)
📌 정리
| 개념 | 요약 | 비유 |
|---|
| UIResponder | 이벤트에 응답 가능한 객체의 기반 클래스 | 이벤트를 받을 수 있는 직원들 |
| Hit Testing | 터치된 뷰를 찾는 과정 | 손님이 가장 가까운 직원 찾기 |
| First Responder | 현재 이벤트(입력)를 받고 있는 객체 | 현재 손님을 응대 중인 직원 |
| Responder Chain | 이벤트를 위로 전달하며 처리하는 경로 | 응대 못하면 옆 직원에게 넘기기 |