[iOS]View의 형성과정(window, rootView, Main함수, Appdelegate)

신용철·2020년 9월 21일
0

iOS_View

목록 보기
1/11

이번 포스트에서는 사용자가 화면으로 볼 수 있는 view가 실제로 어떤 과정에 의해 형성되는지 알아봅니다. 또한, 이 과정에서 iOS.13버전에 어떠한 변화가 생겼는지 설명합니다. 이 부분을 아는 것이 중요한 이유는 가끔 app이 최초 실행 될 때 죽는 경우가 발생할 수 있는데 view가 최초에 형성되는(앱이 최초 실행되는) 과정을 알면 문제를 해결하는데 도움이 될 수 있기 때문입니다.

1. window와 rootView

Window란?

View의 가장 최상위 계층에 있는 것이 바로 window입니다. window는 UIWindow의 instance입니다. window는 모든 view의 가장 위에 존재하는 superView라고 이해하시면 됩니다.

RootView란?

rootView는 window의 속성 중 하나입니다. 사용자가 실제로 볼 수 있는 화면은 rootview의 위에 생성한 View들입니다.

Window와 rootView의 생성

app이 실행되면 UIApplicationMain 함수가 호출됩니다.(Objective-C project와는 달리 Swift에서는 코드로 직접적으로 호출하지 않아도 됩니다.) 이 함수는 app이 구동되는데 가장 기초적이고 중요한 인스턴스들을 생성합니다. 이 중에 window와 rootView가 포함됩니다.

2. App의 실행과정(최초 View의 생성 과정)

1) iOS 13버전 이전( ~ iOS 12버전까지)

  • UIApplicationMain 함수(이후 main 함수라 하겠습니다.)가 실행되면서 UIApplication이 인스턴스화되고 이어서 app delegate class들이 인스턴스화됩니다. UIApplication은 singlton을 선언하고 있기 때문에 UIApplication.share를 통해 해당 인스턴스에 접근할 수 있습니다.

  • main함수는 Info.plist에서 storyboard 사용여부를 확인하고 사용하고 있다면(UIMainStoryboardFile로 식별) storyboard로viewController를 인스턴스화 합니다.

  • main함수는 UIWindow를 인스턴스화해서 app delegate의 window속성에 할당합니다. 그리고 이 window속성의 rootViewController에 main storyboard를 할당합니다.

  • 위의 작업이 모두 끝나면, main함수는 app delegate의 application(didFinishLanuchingWithOptions:)함수를 호출합니다.

  • window와 rootViewController가 정의 되었지만 이 단계에서 아직 화면은 보이지 않습니다. 화면을 보이도록 하기 위해 app delegate에 있는 window 속성을 'key window'로 지정해주어야 합니다. 이를 위해 main함수는 window의 인스턴스 메소드 'makeKyeAndVisible'를 호출합니다.

  • 만약 여러분이 storyboard를 사용한다면 위의 과정은 main함수가 알아서 해주지만, storyboard를 사용하지 않는 경우 위 과정을 AppDelegate.swift 파일에서 직접 code로 구현해야 합니다.

2) iOS 13 버전 이후

  • iOS 12버전과 마찬가지로 main함수가 UIApplication과 app delegate class를 인스턴스화 합니다.

  • 그리고는 12버전과 달리 이전 작업을 하지 않고 곧장application(didFinishLanuchingWithOptions:)메서드를 호출합니다.

  • 위 함수가 호출 된 후에 main함수는 UISceneSession, UIWindowScene, window scene delegate를 인스턴스화 합니다.

  • scene delegate의 class는 Info.plist의 Application Scene Manifest안에 Scene Configuration에서 확인할 수 있습니다.

  • main함수는 Info.plist의 Application Scene Manifest안에 있는 Scene Configuration에서 storyboard의 이름을 확인하여 storyboard 사용여부를 확인합니다. 만약에 값이 있다면 storyboard를 시작 viewController로 인스턴스화 합니다.

  • main함수는 UIWindw를 인스턴스화 하고 이를 scene delegate의 window 프로퍼티에 할당합니다.

  • 이후 main함수는 시작 view controller로 인스턴스화 했던 Main storyboard를 window의 rootViewController로 할당하고 makeKeyAndVisible 메서드를 호출하여 'key window'로 지정하고 화면에 보여줍니다.

  • 이후 scene delegate의 scene(willConnecTo:options:) 메서드가 호출됩니다. 이 메서드를 통해 우리는 launch process가 끝난 직후 화면이 보이기 전에 해야할 작업을 구현할 수 있습니다. 예를 들면, window가 제대로 설정되었는 지 확인할 수 있습니다.

  • iOS 12번과 다른 점은 application(didFinishLanuchingWithOptions:)메서드를 훨씬 일찍 호출한다는 점입니다.

3. Main storyboard를 사용하지 않을 경우 window 및 rootViewController 설정방법

1) iOS 13 버전 이전의 경우에는 application(:didFinishLaunchingWithOptions:), 13버전 이후의 경우 scene(:willConnectTo:options:)에 아래와 같이 설정해줍니다.

func scene(_ scene: UIScene,
   willConnectTo session: UISceneSession,
   options connectionOptions: UIScene.ConnectionOptions) {
       if let windowScene = scene as? UIWindowScene {
           self.window = UIWindow(windowScene: windowScene) 
           let vc = // ...                                  
           self.window!.rootViewController = vc             
           self.window!.makeKeyAndVisible()                 
       }
}

2) MainStroyBoard가 있지만 앱 실행시 UIApplicationMain함수가 보지 못하게 하고 싶은 경우

  • 로그인이 되어있지 않은 경우 메인 화면을 보여주는 대신 로그인 화면을 보여 주고 싶은 경우가 이에 해당 됩니다.
  • 로그인 여부에 따라 보여주고 싶은 시작화면이 다른 경우 아래와 같이 설정할 수 있습니다.
func scene(_ scene: UIScene,
    willConnectTo session: UISceneSession,
    options connectionOptions: UIScene.ConnectionOptions) {
        if let windowScene = scene as? UIWindowScene {
            self.window = UIWindow(windowScene: windowScene)
            let userHasLoggedIn : Bool = // ...
            let vc = UIStoryboard(name: "Main", bundle: nil)
                .instantiateViewController(identifier: userHasLoggedIn ?
                    "UserHasLoggedIn" : "LoginScreen") // *
            self.window!.rootViewController = vc
            self.window!.makeKeyAndVisible()
        }
}
profile
iOS developer

0개의 댓글