항상 앱을 실행하면 대체 어떻게 앱이 실행되는지 그 자체에 대한 궁금증이 있었다. 마치 C언어에서 메인 함수가 시작되면 프로그램이 컴파일 되어 돌아가는 것처럼, uikit의 project에서도 어디에서인가 프로그램이 시작되었으니 프로그램이 돌아갈 것이다. 또한, Storyboard는 빌드하면 우리가 알 필요도 없이 마법처럼 잘 돌아간다. 하지만, 어떻게 앱이 런칭되어서 돌아갈 수 있는지 그 과정을 공부해보자!
Launching 과정을 이해하기 위해 알아야할 기본 개념
UIWindow
Window는 view 계층의 최상위에 위치한다. 그렇다면 Window도 View일까? 맞다. Window도 UIView를 상속받은 View이다. 아이패드와 같은 환경이 아닌, 대부분의 아이폰에서는 하나의 main window만이 존재하고, 아이패드와 같은 뷰에서는 여러개 존재할 수 있다.
시작점은 main 파일이다
뒤의 이해를 위해 Object-C부터 천천히 설명을 해보려고 한다. Object-C 코드는 단 5줄 (그것도 몰라도 된다)뿐이니 겁먹지 말고 찬찬히 읽어보자.
Object-C
앱을 런칭하는 과정에서, 앱의 머신코드를 위치시키고 로딩하고 프레임워크를 링킹하는 과정이 있을 것이고, 어딘가에서 시작될 것이다. Swift 이전의 Object-C에서는 분명한 main 함수와 파일이 있었다. 함수는 아래와 같다.
int main(int argc, char *argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil,
NSStringFromClass([AppDelegate class]));
}
}
이 함수는 @autoreleasepool 이후 클로저를 통해 메모리 관리 환경을 설정하고,
UIApplicationMain(:,:,:,:) 함수를 불러와, 앱이 작동할 수 있도록 무거운 작업들을 수행한다.
@UIApplicationMain
@UIApplicationMain은 위의 main함수가 적힌 main file을 대체한 어노테이션이다. UIApplicationMain을 부르기 위한 엔트리포인트를 표시해 주기 위해 사용된다. UIApplicationMain을 만든후 그 Delegate 객체로 지정해주는 역할을 한다. Swift의 경우에는 main.swift 파일이 불러와진다. @main 또한 동일한 역할을 한다.
App Based
아래 과정들을 이해하면 왜 Scene Based가 나왔는지, 그리고 Scene Based에서는 무엇이 달라졌는지 쉽게 이해할 수 있다.
With StoryBoard
스토리보드와 함께 앱이 런칭되는 과정을 살펴보자.
- 먼저, 메인 함수가 UIApplicationMain() 함수를 실행시킨다.
2. UIApplicationMain() 함수가 UIApplication과 AppDelegate를 인스턴스화 한다.
여기서 UIApplication은 앱의 중앙화된 관리자 역할을 하는 녀석이라고 보면 되고, 그에 대한 알림들을 deleagte받는 녀석이 AppDelegate라고 보면 된다. @main 어노테이션으로 어느 녀석이 UIApplication의 대리자인지 찾아낼 수 있다. UIApplicationMain은 app delegation 인스턴스를 유지시키고, 대리자를 위임하는 역할을 한다.
3. Info.list 체크 및 storyboard 사용
스토리보드를 사용하는지 안하는지를 Info.list의 “Main storyboard file base name” 항목을 체크해서, 스토리보드가 있을 경우 스토리 보드를 Main Interface 값으로 로드를 한다.
4,5. UIApplicationMain()이 UIWindow와 UIViewController를 인스턴스화 한다.
여기서 storyboard가 있을때, 자동적으로 window와 viewcontroller를 UIKit이 만들어 주고, UIWindow는 UIView의 가장 상위 계층에 위치하게 된다. 이때 window가 앱이 꺼지기 전까지 유지될 수 있도록 하고, window가 디바이스의 화면을 채울 수 있는 사이즈가 되도록 조정하는 역할을 한다. 이 과정에서 screen의 bounds를 window의 frame에 맞추도록 한다.
또한, ViewController를 만들어 Window의 rootViewController가 스토리보드의 뷰 컨트롤러가 될 수 있도록 설정해 준다. 이때, ViewController의 main view (우리가 뷰 컨트롤러에서 self.view로 불러오는 view)를 Window의 하나의 subView로 설정해준다.
6. AppDelegate에 launching이 끝났으니 할일을 알려달라는 알림
런칭 과정이 거의다 끝났으니, 커스텀 할만한 일들을 사용자가 AppDelegate의 application(:didFinishLaunchingWithOptions:)에 정의해 두었다면 그것을 실행한다.
7. Window의 makeKeyAndVisible() 메서드를 Window가 호출한다.
Window의 makeKeyAndVisible() 메서드를 불러, window를 key window로 지정하고, visible하도록 설정을 해준다. 이 설정을 해주지 않으면 app의 key window가 설정이 되어있지 않아, 앱의 인터페이스가 보이지 않는다.
Without Storyboard
위의 스토리보드가 있을때의 그림과 별반 다르지 않은 그림이라는 것을 알 수 있다. 하지만 여기 4번에서 부터 Info.plist에서 메인 스토리보드 파일을 찾을 수가 없어 이후의 과정들이 달라진다. 스토리보드가 있을때 UIKit이 자동적으로 인스턴스를 만들어주는 것과 달리, application 메서드 내에서 사용자가 직접 Window와 ViewController를 만들어 준 후에 rootViewController로 지정해주는 과정을 거쳐야 스토리보드 없이 코드로 UI 작업을 할 수 있다. 그 코드는 우리가 일상적으로 써온 (iOS 12전에서) 아래 코드다.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let window = UIWindow(frame: UIScreen.main.bounds)
window.rootViewController = ViewController()
window.makeKeyAndVisible()
self.window = window
return true
}
UIKit에서 자동적으로 UIWindow와 rootViewController 지정 그리고 makeKeyAndVisible()을 불러준 것과 달리 AppDelegate의 메서드에서 UIApplication과 AppDelegate 인스턴스가 만들어진 이후에 manual로 직접 지정해주고 true를 리턴해주는 방식이다. 사실상 자동화가 되어있냐, 되어있지 않냐의 차이밖에 보이지 않는다.
이렇게 App Based의 Launch 과정을 알아보았다. 다음은 Scene Based의 Launch 과정을 알아보겠다. 이해안되는 부분이나 틀린 부분이 있다면 댓글 부탁드려요~