ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • @main vs @UIApplicationMain
    iOS 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

     

    GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhancements to the Swift Programming Lang

    This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - GitHub - apple/swift-evolution: This maintains proposals for changes and user-visible enhance...

    github.com

    https://medium.com/@abedalkareemomreyh/what-is-main-in-swift-bc79fbee741c

     

    What is @main in Swift

    In all programs you always have an entry point, a place where your app should start from, and swift is no exception to that. If you…

    medium.com

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

     

    Declarations — The Swift Programming Language (Swift 5.7)

    Declarations A declaration introduces a new name or construct into your program. For example, you use declarations to introduce functions and methods, to introduce variables and constants, and to define enumeration, structure, class, and protocol types. Yo

    docs.swift.org

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

     

    Apple Developer Documentation

     

    developer.apple.com

Designed by Tistory.