개발을 시작하는 이야기

@main 본문

개발 이야기/Swift

@main

Teiresias 2022. 3. 21. 18:03

What is @main in Swift

모든 프로그램에는 항상 시작하는 진입점이 있으며 Swift도 예외는 아니다.

@main은 스위프트 5.3 버전에서 구현된 범용적인 엔트리 포인트 기능이이다.

 

이전 버전에서는 앱 개발용 프로그램을 위해서는 @UIApplicationMain이라는 어트리뷰트로 엔트리포인트를 지정했다.

import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate { ... }
//XCode 11(Swift 5.2)이전의 @UIApplicationMain

 

import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate { ... }
//XCode 12(Swift 5.3)이후의 @main

해당 변경 사항은 Apple의 Swift - evolution 레포지토리에 2020년 3월에 처음 제안되었다.

출처: Github - Apple

소개글을 보자면 프로그램 실행 시작 시 진입점으로 타입을 지정하기 위한 스위프트 언어의 기능이라고 나와있다.

탑 레벨의 코드를 작성하는 것 대신 사용자는 Single type에 @main 속성을 사용할 수 있고, 라이브러리와 프레임워크는 프로토콜과 클래스 상속을 통해 앱의 진입점을 커스텀 할 수 있다고 한다.

 

그러면 탑 레벨 코드를 공식문서를 찾아보면 다음과 같이 설명하고 있다.

Swift 소스 파일에서 탑 레벨 코드는 0개 이상의 선언이나 정의 그리고 표현식으로 구성되어 있다고 한다. 기본적으로 소스파일의 탑 레벨에서 선언된 것들은 같은 모듈내의 모든 소스파일에서 접근할 수 있다. 

탑 레벨 코드에는 탑 레벨 선언(top-level declarations)실행가능한 탑 레벨 코드(excutable top-level code)가 있는데, 이 중 소개글에서 설명하는 탑 레벨 코드는 실행가능한 탑 레벨 코드를 의미하고 오직 프로그램의 진입점으로서만 허용된다.

 

그러니 결국 처음에 의미한 탑 레벨 코드는 기존의 진입점을 알려주는 @UIApplicationMain 속성인 것이다.

@UIApplicationMain

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

 

그러나 Xcode에서 새 iOS 프로젝트를 만들고 앱이 어디서 부터 시작되는지 알기위해 main() 함수 혹은 "main.swift" 파일을 찾아보면 쉽게 찾을수가 없다. 그 이유는 iOS 기본 템플릿에선 Swift 파일에 @UIApplicationMain을 포함함으로써 컴파일러가 iOS 앱의 진입점을 합성하기 때문에 따로 "main.swift" 파일이 필요하지 않기 때문이다.

 

그렇다고 main() 함수가 존재하지 않는 것은 아니다. Swift 기반의 iOS 프로젝트에서는 UIKit 프레임워크가 이를 숨겨서 관리하기 때문에 찾기 힘든것이다.

@UIApplicationMain 함수

@UIApplicationMain은 UIApplicationMain 함수를 호출하고 해당 클래스의 이름을 델리게이트 클래스의 이름으로 전달한다. 

 

 

 

이 함수는 앱 실행에서 중요한 몇가지 기능을 수행한다.

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

이제 @UIApplicationMain의 역할과 함수 기능에 대해 살펴보았으니 @main을 사용하게 되었는지 알아보자.

@main

스위프트의 프로그램은 소스파일의 시작점부터 시작해 특별한 구문 없이 잘 작동한다. 그러나 사용자용 앱의 경우 종료될 때 까지 계속해서 실행되고, UIKit이나 AppKit과 같은 사용자 인터페이스 프레임워크는 앱 실행의 복잡성을 처리하여 앱 동작을 정의하기위한 고급의 API 후크를 제공하게 된다. 이러한 프레임 워크를 사용하는 개발자는 일반적으로 앱 실행의 문자 그대로의 시작점에 대해 신경 쓰거나 상호 작용하지 않는다.

 

이 두 모델을 해결하기 위해 앱은 프레임워크의 기본 실행 시작점을 시작하기 위해 소량의 "부팅 코드"가 필요로 하게 된다. 초기 릴리스 이후 Swift는 시작 프로세스를 원활하게 수행하기 위해 @UIApplicationMain 이나 @NSApplicationMain 으로 부팅 로딩을 제공했다.

 

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

 

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

 

정리를 하자면

@UIApplicationMain을 대신하여 @main 속성을 사용함으로써 타입 기반의 스위프트 코드에서 이상적인 프로그램 진입점을 알려줄 수 있고 main() 함수는 일반 정적 메서드이므로 프로토콜에서 확장 메서드 또는 기본 클래스로 제공할 수 있다. 이를 통해 프레임 워크는 추가 언어 기능 없이도 사용자 지정 진입점 동작을 쉽게 정의 할 수 있게 된다.

 

어떤 UI프레임워크이던 상관없이 특정한 목적을 위한 속성보다 @main을 사용함으로서 일관성을 추구하고 더욱 간편한 진입점을 제공하게 된다. @main이 범용적인 이유는 단일 파일 코드이던, 프레임워크 프로젝트이던, 커스텀 라이브러리던 상관없이 동일하게 엔트리포인트를 제공해줄 수 있기 때문이다.

 

참조 : https://docs.swift.org/swift-book/ReferenceManual/Declarations.html

참조 : https://developer.apple.com/documentation/uikit/1622933-uiapplicationmain

'개발 이야기 > Swift' 카테고리의 다른 글

XIB를 활용하기  (0) 2022.03.23
StoryBoard를 사용하기  (0) 2022.03.22
앱 시닝(app thinning)  (0) 2022.03.20
weak, unowned  (0) 2022.03.19
ARC(Automatic Reference Counting)  (0) 2022.03.18