@main

Tabber·2022년 1월 13일
1

iOS Review

목록 보기
11/15

공부하며 적는 글입니다. 정확하지 않을 수 있습니다.

얘는 또 뭐야

@main
이건 어디에 사용하는 것이고, 그 뜻은 뭘까..

공식문서를 찾아보자

@main: Type-Based Program Entry Points

공식문서에 따르면 @main 은 타입 기반의 프로그램 진입점 이라고 설명한다.

프로그램 실행을 시작하기 위한 진입점으로 타입을 지정하는 Swift 언어 기능이라고 한다.

대충 프로그램이 시작할때를 지정해주는 키워드인듯 하다.
그럼 어디서 사용할까?

보통 우리가 @main 을 볼 수 있는 곳은 AppDelegate 클래스이다.
AppDelegate는 앱이 시작되는 진입점을 알려주고, 앱의 입력 이벤트를 전달하는 런루프를 생성하는 역할을 한다.

그리고 @main 은 Swift 5.3 버전 부터 사용하는 키워드이다.
그전에는 @UIApplicationMain 이라는 키워드로 사용하고 있었다.

소개를 조금 자세히 보면, 탑 레벨의 코드를 작성하는 대신 사용자는 싱글타입에 @main 속성을 사용할 수 있다고 설명한다. 또한 라이브러리와 프레임워크는 프로토콜과 클래스 상속을 통해 앱의 진입점을 커스터마이징할 수 있다고 한다.

이게 뭔말이냐;

일단 탑 레벨 코드가 뭔지부터 알아보자.
문서 얘기하는 탑 레벨 코드는 0개 이상의 선언이나 정의 그리고 표현식으로 구성된다고 한다. 기본적으로 소스파일의 탑 레벨에서 선언된 것들은 같은 모듈내의 모든 소스파일에서 접근이 가능하다는 것이다.

이 탑 레벨 코드에는 두 가지 종류가 존재한다고 한다.
탑 레벨 선언실행가능한 탑 레벨 코드 이다.

이 중에서 실행가능한 탑 레벨 코드는 오직 프로그램의 진입점으로서만 허용된다고 한다.

따라서 우리가 아까 소개에서 봤던 탑 레벨 코드의는 기존의 진입점을 알려주는 @UIApplicationMain 속성이었다라는 것을 알 수 있다.

그럼 @main 을 알기전엔 그 전에 사용했던 걸 알아야 하지 않겠는가?

@UIApplicationMain

Objective-C 기반의 프로젝트에서는 main.m 의 소스파일에 있는 main() 함수를 프로그램이 시작되고, Swift 기반의 Xcode 프로젝트에서 Mac 템플릿을 생성하면 기본적으로 main.swift 파일을 포함하여 main 함수를 쉽게 찾아볼 수 있다.

그런데, Xcode에서 새 iOS 프로젝트를 만들고 앱이 어디서부터 시작되는지 알기 위해 main 함수를 찾아보려고 하면, 뭐 잘 보이지도 않는다.

그 이유는 iOS 기본 템플릿에서는 Swift 파일에 @UIApplicationMain 을 포함함으로써 컴파일러가 iOS의 진입점을 합성하기 때문에 main.swift 파일이 필요하지 않았던 것이다!

그렇다고 main() 함수가 없는건 아니다. Swift 기반의 iOS 프로젝트에서는 UIKit 프레임워크가 이를 숨겨서 관리하고 있기 때문에 찾기가 힘들었던 것이다.

UIApplicationMain 함수

@UIApplicationMainUIApplicationMain 함수를 호출하고 해당 클래스의 이름을 delegate Class의 이름으로 전달한다.

이 함수는 앱 실행에서 중요한 기능들을 수행하게 된다.

  • 앱의 본체에 해당하는 객체 UIApplication 객체를 생성하고, 앱의 Life Cycle을 관리하게 된다.
  • 지정된 클래스(@UIApplicationMain 이 표시된 곳)에서 Delegate를 인스턴스화 하고 이를 앱의 객체에 할당한다.
  • 앱의 Run Loop를 포함한 기본 이벤트처리 루프를 설정하고 이벤트 처리를 시작한다.
  • 앱의 info.plist에 불러올 main nib파일이 제대로 명시되어 있으면, 해당 nib을 불러오게 된다.

앱을 실행하기 위한 제일 중요한 부분들이 여기에서 실행되는 것이었다.

그럼 @UIApplicationMain 의 역할과 함수의 기능에 대해서 알아보았으니, 왜 @main 을 사용하게 됐는지 알아보자.

@main

스위프트의 프로그램은 소스파일의 시작점 부터 시작해 특별한 구문 없이 잘 작동하게 된다.

근데, 사용자용 앱의 경우 종료될 때 까지 계속해서 실행되고, UIKit이나 AppKit과 같은 사용자 인터페이스 프레임워크는 앱 실행의 복잡성을 처리하여 앱 동작을 정의하기 위한 고급의 API 후크를 제공하게 된다.

이런 프레임워크를 사용하는 개발자는 앱 실행의 문자 그대로 시작점에 대해 신경 쓰거나 상호 작용하지 않는다.

이 두 모델의 문제를 해결하기 위해서, 앱은 프레임워크의 기본 실행 시작점을 시작하기 위해 소량의 "부팅 로딩" 코드가 필요로 하게 된다.

그래서 초반에 Swift가 나왔을 때는 @UIApplicationMain 이나 @NSApplicationMain 로 부팅로딩을 제공했었다.

근데 이렇게 조금 길고 직관적이지 않은 코드를 사용하기 보단 @main 과 같은 더 일반적이고 가벼운 메커니즘을 제공하는 것이 더 이상적이라고 생각해서 만들었다고 한다.

이는 스위프트의 타입 기반의 시스템을 사용하여 문제를 해결하는 패턴에 더 적합하다고 한다. 그리고 프레임워크가 표준 언어 기능을 사용하여 깔끔하고 간단한 진입점을 제공할 수 있게 한다.

정리

@UIApplicationMain 대신 @main 속성을 사용함으로써 타입 기반의 스위프트 코드에서 이상적인 프로그램의 진입점을 알려줄 수 있고, main() 함수는 일반 정적 메서드 이므로 프로토콜에서 확장 또는 기본 클래스로 제공할 수 있다.

profile
iOS 정복중인 Tabber 입니다.

0개의 댓글