-
@main vs @UIApplicationMainiOS 2022. 7. 21. 09:32
안녕하세요. 그린입니다🟢
이번 포스팅에서는 @main과 @UIApplicationMain이 무엇인지 그리고 어떤 차이가 있는지 학습해보겠습니다🙌
swift 5.3 이전부터 Xcode를 통해 프로젝트를 만들어보시고 경험해보신분이라면 이 두 키워드에 대해 모두 보셨을거에요.
그럼 실제적으로 이 두 키워드는 어떤 친구고, 무슨 차이이며 어떤걸써야하는지에 대해서 정리해보겠습니다!
@main
쉽게 말해 이 키워드는 프로그램의 진입점을 나타내줍니다.
어느 프로그램이던지 시작점 즉 Entry Point는 존재해야하죠.
Swift에서는 @main을 통해 어디서부터 이 앱이 최초 실행되고 시작될지를 명시해주는 키워드입니다.
이 키워드는 Swift 5.3 이상(Xcode 12)부터 사용된 키워드로 바로 이어서 설명하겠지만 @main 키워드가 나오기 전에는 @UIApplicationMain 키워드를 사용하고 있었어요.
그럼 UIKit과 SwiftUI로 나눠 어디서 실제적으로 구성되어 있는지 구체적으로 알아보시죠!
import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { ... }
이렇게 UIKit의 라이프사이클로 앱을 만들면 AppDelegate 클래스에 @main이 붙게됩니다.
AppDelegate가 사실상 App Life Cycle을 관리하는 모든 주체이기에 여기에 @main 키워드가 붙어 사용되는게 당연할거에요🙌
import SwiftUI @main struct SwiftUIApp: App { ... }
마찬가지로 SwiftUI 라이프사이클을 따르는 앱을 만들면 실제로 App 구조체에 @main이 붙게되죠.
SwiftUI로 구성된 앱에서는 각 View 타입의 실제적인 뷰 인스턴스가 있을것이고 이는 App 프로토콜을 따르는 메인앱 구조체 타입에 정의되어 있을거에요.
즉 여기서는 SwiftUIApp 구조체가 실제적인 앱 실행 시 처음 마주치는 AppDelegate와 같은것으로 볼 수 있기에 @main 키워드도 여기를 시작 진입점으로 기본 설정되있는걸 확인할 수 있습니다.
그럼 우리는 사실 이런걸 알고 있어요.
main() 즉 메인 함수를 통해서 시작 지점을 알려주고 실행해주는걸요.
콘솔 기반의 코드를 작성하게 되면 사실 main()을 통해 실행시켜주는걸 알 수 있고 이게 진입점이라고 볼 수 있습니다.
그런데 왜 @main일까요?
그건 UIKit 프레임워크에 존재하기에 @main 키워드를 사용하는것이 메인 함수를 사용하는걸 내포하고 있는거라 볼 수 있습니다.
@UIApplicationMain
그럼 이어서 @UIApplicationMain이 무엇인지 비교해보죠.
우선 위에서도 언급하긴 했지만 Swift5.3(Xcode 12) 이전에는 @UIApplicationMain를 사용했습니다.
역할은 당연히 동일하겠죠?
앱의 라이프사이클을 관리하기위한 UIApplication 객체 생성을 위한 키워드라고 볼 수 있어요.
즉 아래와 같이 사용해도 사실 무방하고 빌드에 이상은 없다는 소리죠.
import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { ... }
다만 SwiftUI로 구성된 앱 진입점으로 해당 키워드를 사용하면 이렇게 에러를 뱉습니다.
해당 키워드는 오직 클래스에서만 선언될 수 있다고 해요.
그럼 왜 이런 에러를 발생시키고 어떤 차이가 있는지 살펴보죠!
@main vs @UIApplicationMain
우선 이 두 키워드가 하는 역할은 맥락은 같음을 위에서 간단히 이해해봤어요.
@main이 소개된 공식 깃헙의 문서를 보면 타입 기반이라고 명시되어 있습니다.
@main 키워드를 사용하면 Top-Level 코드 작성을 대체할 수 있다고 해요.
여기서 말하는 Top-Level 코드란 무엇일까요?
요 공식문서에 설명이 잘 나와있는데요.
https://docs.swift.org/swift-book/ReferenceManual/Declarations.html
간단히 요약해보자면, Swift 소스 파일의 Top-Level Code는 0개 이상의 명령문, 선언 및 표현식으로 구성됩니다.
기본적으로 소스 파일의 Top-Level Code에서 선언된 변,상수 및 그 외 선언은 동일 모듈의 일부인 모든 소스파일의 코드에서 엑세스 할 수 있다고 합니다.또한 이 기본 동작을 재정의할 수도 있습니다.
Top-Level Code에는 Top-Level 선언과 실행 가능한 Top-Level Code 두가지로 나눌 수 있습니다.
선언은 선언만으로 구성되어 모든 Swift 소스 파일에서 허용됩니다.
반면 실행 가능한 Top-Level Code는 선언뿐만 아니라 명령문 및 표현식이 포함되며 프로그램의 최상위 진입점 말 그대로 Entry Point로만 허용됩니다.
그렇기에 @main 전에 @UIApplicationMain 속성을 통해 실행 가능한 Top-Level Code로 사용되며 앱의 진입점으로 활용된걸 알 수 있습니다.
그럼 돌아와서 UIApplicationMain 함수를 조금 볼께요.
이 메서드의 선언은 아래와 같아요.
func UIApplicationMain( _ argc: Int32, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<CChar>?>, _ principalClassName: String?, _ delegateClassName: String? ) -> Int32
보시면 클래스 이름을 파라미터로 받아요.
즉 클래스에서 사용될 수 있는 함수일것이고 이 함수는 실제적으로 UIApplication 객체를 생성하게 됩니다.
기존 사용되던@UIApplcationMain 키워드는 클래스에서만 사용가능한것의 이유가 될 수 있을것 같아요.
그럼 정말 최종적으로 다시 돌아와서 @main을 사용하게 된 이유가 어떤게 있을지 파악해보죠.
흐름을 정리해보면 아주 예전으로 거슬러가면 옵젝씨 시절일때 iOS 앱은 main.m 소스파일에 main() 함수가 있었습니다.
이 함수로 인해 앱의 진입점을 나타내며 시작하게 됩니다.
그러다가 Swift로 언어가 넘어오면서 main.swift에서 이 main 함수가 동일 역할을 해주게 됩니다.
그와 동시에 UIKit 프레임워크안에 이 main 함수를 넣어 관리하고 우리는 @UIApplicationMain 키워드만을 사용하게 된것이죠.
그렇게 됨으로 자동으로 컴파일단에서 이 키워드를 찾고 인식하게 되었던것이에요.
그리고 찐막으로 @main이 나오면서 그걸 사용하게 된 아주 함축된 흐름을 우선 정리해봤습니다.
기존 @UIApplicationMain를 사용한다면 위에서 발생한것처럼 클래스에서만 사용이 가능했죠.
이 문제는 타입 기반의 Swift 코드에서는 미스매칭이 있었고 이를 해결하기 위해 @main 속성을 사용함으로 해결해주었어요.
main() 함수 자체가 static 메서드(타입 메서드)이기에 프로토콜에서 확장 메서드 및 기본 클래스로 제공될 수 있습니다.
그말은 아주 커스텀하게 원하는곳에서 @main을 통해 진입점을 제공해줄 수 있다는 말과 같아요.
정리해보자면 @main을 사용함으로 기존 @UIApplicationMain을 사용할때보다 타입 기반의 코드에서 더 알맞은 앱 진입점을 표현해줄 수 있으며 타입 메서드인 static func main()을 통해 확장 및 기본 클래스로 제공되며 사용할 수 있는 장점을 가지게 됩니다.
그렇기에 이제 사실 Swift 5.7이 나온 상황에서 @UIApplicationMain을 사용하기보다는 @main을 사용하는것이 더 많은 이득을 취할 수 있을거라 생각이 됩니다.
마무리
간단한 결론을 도출하기까지 Object-C부터 어떻게 사용되어왔고 어떻게 발전되었는지 파악하기에 꽤 리소스가 들었네요!
너무 당연하게 의심없이 사용하던걸 다시 돌아보는 좋은 계기였습니다🙌
[참고자료]
https://github.com/apple/swift-evolution/blob/main/proposals/0281-main-attribute.md
https://medium.com/@abedalkareemomreyh/what-is-main-in-swift-bc79fbee741c
https://docs.swift.org/swift-book/ReferenceManual/Declarations.html
https://developer.apple.com/documentation/uikit/1622933-uiapplicationmain
'iOS' 카테고리의 다른 글
프로젝트 파일 구조 및 네이밍에 대해 (with. TCA & Coordinator 패턴) (4) 2022.08.20 NSCache vs URLCache (0) 2022.08.01 UIKit에서 SwiftUI로 LifeCycle 변환하기 (0) 2022.07.14 새로운 앱을 만들기 위한 기술스택 선정하기 (4) 2022.06.30 앱 출시 - 몽실(Mong:seal) (0) 2022.06.27