iOS 13이전에는 AppDelegate가 화면과 함께 앱의 생명주기(Life-Cycle)을 담당했습니다. 하지만 iOS13부턴 Scene Delegate가 도입되면서 어느정도 역할이 분배 되었는데 여기서 무엇이 어떻게 달라졌는지와 생명주기에 대한 내용까지 다뤄보고자 합니다.
ABOUT 생명주기(Life- Cycle)
앱은 실행되는 동안 다양한 상태로 변화합니다. 여기서 말하는 상태는 화면에 나타났거나, 화면에서 숨겨지거나 시작했거나 종료됐거나 하는 등을 의미합니다.
앱의 상태변화는 운영체제가 처리하는 영역입니다. 아이폰의 경우 iOS 운영체제가 시스템의 상황에 맞게 발생하는 상황에 맞춰 앱의 상태를 변화시키고 제어합니다. 예를 들면 모바일 게임을 하는 도중 전화가 오면 실행되는 앱이 화면에서 사라지고 통화화면이 실행되는 것 그리고 통화가 끝나면 다시 게임으로 화면이 돌아오는 것 이러한 일련의 과정을 상태 변화라고 합니다.
이러한 상태변화를 iOS는 총 5가지로 나눕니다.
- Unattached(Not Running) - 앱이 시작되지 않았거나 실행되었지만 시스템에 의해 종료된 상태
- Inactive - 앱이 전면에서 실행중이지만, 아무런 이벤트를 받지 않고 있는 상태(런치 스크린 and 앱 키고 가만히두면 화면이 자동으로 꺼지는 경우)
- Active - 앱이 전면에서 실행중이며, 이벤트를 받고 있는 상태
- Background - 앱이 백그라운드에 있지만 여전히 코드가 실행되고 있는 상태(대부분 Suspended 상태로 이행하는 도중 일시적으로 이 상태에 진입함)
- Suspended - 앱이 메모리에 유지되지만 실행되는 코드가 없는 상태(메모리 부족한 경우 자동으로 제거됨)
위와 같은 과정을 앱의 생명주기(Life-Cycle)라고 합니다. 하나의 상태에서 다른 상태로 옮겨가는 중일 때는 상태변화라고 합니다.
AppDelegate의 메소드 호출
위에서 설명한 앱의 실행 상태가 변화할 때마다 앱 객체는 앱 델리게이트에 정의된 특정 메소드를 호출하게됩니다. 우리는 이 메소드를 적절하게 사용해 앱이 종료되기 직전에 데이터를 저장하는 것, 백그라운드에 내려가면 필요없는 메모리를 정리하는 것 등의 기능을 사용할 수 있습니다. 이와 관련해 주요 메소드를 살펴보겠습니다.
1. Unattached(Not-Running) 상태
application(_:willFInishLaunchingWithOptions:)
앱이 실행되어 초기 실행과정이 완료되기 직전에 호출되는 메소드입니다.
application(_:didFinishLaunchingWithOptions:)
앱이 최초로 실행될 때 호출되는 메소드로, 앱이 사용자에게 화면으로 표시되기 직전에 호출되는 메소드입니다. 주로 초기화 코드를 이 곳에 작성하며 Not Running에서 Foreground로 상태가 변환하게 됩니다.
applicationWillTerminate(_:)
앱이 종료되기 직전에 호출되는 메소드입니다. 사용자 데이터등을 종료 전에 한 번 더 저장해두는 것이 좋습니다.(단, suspended 상태에서는 호출되지 않습니다.)
2. Inactive 상태
applicationWillEnterForeground(_:)
앱이 Background에서 Foreground로 진입할 때 호출되는 메소드입니다. 앱이 Background에서 Foreground로 돌아오기 직전, 화면에 보여지기 직전에 호출되며 호출된 뒤 Inactive 상태를 거쳐 Active 상태로 진입하게 됩니다.
applicatioWillResignActive(_:)
앱이 Active에서 InActive상태로 바뀔때 호출되는 메소드입니다.(Inactive 상태로 바뀌기 직전에 호출)
sceneWillEnterForeground(_:)
앱이 Background나 Not-Running 상태에서 foreground로 들어가기 직전에 호출되는 메소드입니다.
3. Active 상태
applicationDidBecomeActive(_:)
앱이 Active될 때 호출되는 메소드입니다. 앱이 Inactive상태에 들어가면서 일시 중지된 작업이 있는 경우 이를 재시작하는 코드를 여기에 반드시 작성해 줘야합니다. 예를들어 타이머나 스톱워치 앱의 경우 Inactive 상태로 들어가면 화면갱신이 이루어지지 않고 예전화면이 유지되기 때문에 이 메소드를 통해 화면과 시간들을 갱신해 주어야 합니다.
sceneDidBecomeActive(_:)
앱이 비활성화 상태에서 활성화 상태로 진입하고 난 직후 호출되는 메소드입니다.
4. Background 상태
applicationDidEnterBackground(_:)
앱이 background 상태일 때 호출되는 메소드 입니다. 앱이 언젠가 종료될 것(Suspended >> Not Running)을 뜻하기에 잃어서는 안되는 사용자 데이터를 저장하거나, 공유 자원을 점유하고 있었다면 해제해 주어야 합니다. 종료된 앱이 다시 실행될 때 현재의 상태를 복구할 수 있도록 필요한 상태 정보도 이 메소드에서 저장 처리하는 것이 좋습니다.
sceneDidEnterBackground(_:)
앱이 background 상태일 때 호출되는 메소드입니다. Suspended 상태가 되기 전 중요한 데이터를 저장하는 등의 종료 직전에 필수적으로 해야하는 작업을 이 메소드에서 합니다.
5. Suspended 상태
따로 호출되는 메소드는 없으며 Background 상태에서 특별한 작업이 없을 때 이 상태가 됩니다. 메모리가 부족한 경우 iOS에서 알아서 앱을 종료해 공간을 확보해줍니다.
함수가 다소 복잡해 보이지만 Will이 들어가면 상태에 들어가기 직전을 뜻하고 Did가 들어가면 상태에 들어가고 난 직후라고 기억하면 조금 쉽게 기억이 가능할 거 같습니다.
iOS 12와 13의 차이(feat. SceneDelegate의 등장)
iOS12에서 iOS13으로 넘어오면서 큰 변화가 생겼습니다. 바로 SceneDelegate의 등장입니다. 이전까지는 AppDelegate가 모든 생명주기 관련 이벤트들을 담당했습니다. 프로젝트를 만들면 생성되는 AppDelegate.swift파일입니다.
기존의 App Delegate는 Process Life Cycle과 함께 UI Life Cycle을 기능을 같이 담당하고 있었습니다. 즉 앱의 내부적인 실행, 종료, 대기 등의 상태와 함께 화면에 보여주는 뷰의 등장, 사라짐 등의 사건등을 모두 담당했다고 보면 되겠습니다.
iOS 13이후부턴 SceneDelegate가 등장했습니다. 아이패드에서 여러화면을 띄울 수 있도록 하기위해 등장한 녀석입니다. UI의 생명주기를 담당해 관리해주는 이 녀석이 등장한 이후로 하나의 앱에서 여러 개의 창(Window)를 동시에 사용할 수 있게 되었습니다.
여기서부터 Window(화면)의 개념이 scene으로 바뀌고 SceneDelegate는 기존의 App Delegate에 있던 UI LifeCycle의 기능을 받아 각 Scene을 관리합니다. 대신 추가적으로 AppDelegate에 Scene에 대한 정보를 관리하는 Session LifeCycle이 추가되었습니다.
이로인해 사용자나 시스템이 새로운 scene를 만들어달라고 요청했을 때 UIKit은 scene를 만들어 Unattached상태로 만듭니다. 사용자가 요청한 scene은 바로 Foreground 상태를 거쳐 Active 상태가 되고, 시스템이 요청한 Scene은 보통 Background 상태가 되어 이벤트를 처리한 뒤 Foreground로 올라옵니다.
즉, 사용자가 앱의 UI를 해제하면 UIKit은 연결된 장면을 Background 상태로, 결국 Suspended 상태로 전환합니다. UIKit은 언제든 Background 또는 Suspended된 Scene의 연결을 끊어 리소스를 회수할 수 있고, Scene을 연결되지 않은 상태로 되돌릴 수 있습니다.
SceneDelegate가 없는 버전의 경우는???
요즘 iOS13.0 이전 버전을 사용하는 유저는 거의 없겠지만 극소수는 존재할거라 생각합니다... 하지만 우리가 프로젝트를 만들면 자동으로 SceneDelegate.swift파일이 생겨 13.0 이전 버전을 테스트하는 경우 오류가 발생하게됩니다. 이와 같이...
이러한 오류를 해결해주려면 어떻게해야할까요??? 바로 @available구문의 사용입니다:)
가장먼저 SceneDelegate 클래스 위에 @available(iOS 13.0, *)을 붙여줍니다.(iOS 13.0 이상 버전부터 사용하겠다는 의미입니다) available 관련 포스팅은 여기로 >> https://josee2.tistory.com/13
위에서 설명했듯 전에는 AppDelegate가 SceneDelegate의 역할을 했으니 그에 따른 함수를 AppDelegate에 다시 추가해줌과 동시에 추가된 scene session에 대한 부분도 수정을 해줘야합니다.
Scene session에 available 구문을 추가해주고 기존 App Delegate의 함수는 아직 남아있으니 필요한데로 가져다가 사용하면 SceneDelegate를 굳이 삭제하지 않아도 빌드가 됩니다.
참고
꼼꼼한 재은씨의 Swift 기본편
'iOS' 카테고리의 다른 글
[iOS] WKWebView (0) | 2022.07.28 |
---|---|
[iOS] 컬렉션뷰(Collection View) (0) | 2022.07.21 |
[iOS] TableViewController - Custom Table View Cell (0) | 2022.07.19 |
[iOS] TableViewController - System Cell (0) | 2022.07.18 |
@IBOutlet @IBAction에 대하여 (0) | 2022.06.17 |