"App Life Cycle"

앱의 실행부터 종료까지의 주기이며,

- 앱이 화면에 보이고 있는 foreground (Active)

- 앱이 화면에 보이지 않고 실행되고 있는 background

- 앱이 실행 중이지만, 아무런 이벤트가 없는 InActive (ex. 전화)

- 앱이 background에 있지만, 실행되는 코드가 없는 상태인 Suspend

    - 메모리가 부족한 상황이 오면 이 상태에 있는 앱들을 특별한 알림 없이 정리한다.

- 실행되지 않은 상태인 Not Running 

이 있다.

-> Active와 InActive를 합쳐서 Foreground 상태라고 한다.

 

상태 변화

iOS는 시스템에서 발생하는 특정 상황에 맞게 앱의 상태를 변화시키고 제어한다.

ex) 우리가 카카오톡을 사용하다가, 친구에게 전화가 오면 카톡이 꺼지고 '전화 앱'이 켜지는 상황을 보셨을 것이다.

이는 iOS가 '전화'라는 상황에 맞게 앱의 상태를 변경한 것이다.

 

이처럼 iOS는 각각의 앱마다 상태 변화를 제어하여 어떤 앱은 실행시키고, 어떤 앱은 홈 화면으로, 종료를 하는 등 다양한 처리를 한다.

 

앱 상태에 따른 메소드 ( ~ iOS 12 )

앱의 상태가 변화할 때마다 앱 객체는 AppDelegate에 정의된 특정 메소드를 호출한다.

AppDelegate는 앱의 모든 Window를 관리한다.

 

  • application(_:willFinishLaunchingWithOptions:)
    • 앱이 구동되어 필요한 초기 실행 과정이 완료되기 직전에 호출되는 메소드
  • application(_:didFinishLaunchingWithOptions:)
    • 앱이 사용자에게 화면으로 표시되기 직전에 호출되는 메소드
    • 앱이 실행된 후에 진행할 초기화 작업들을 주로 수행
  • applicationDidBecomeActive(_:)
    • 실행된 앱이 화면 전면에 표시될 때 호출되는 메소드
    • 앱이 InActive 상태에 들어가면서 일시 중지된 작업이 있다면, 재시작 코드를 여기서 작성해야 한다.
    • ex) 타이머 앱의 경우, InActive 상태로 들어가면 더이상 화면 갱신이 이뤄지지 않기 때문에, 이 메소드에서 갱신해야 함
  • applicationDidEnterBackground(_:)
    • 앱이 Background 상태에 진입했을 때 호출되는 메소드
    • 이 메소드가 호출되면 미래에 앱이 종료될 가능성이 있다는 뜻이므로, 사용자의 데이터를 미리 저장하거나, 공유 자원을 해제해야 함
  • applicationWillTerminate(_:)
    • 앱이 종료되기 직전에 호출되는 메소드

 

앱 상태에 따른 메소드 ( iOS 13 ~ )

Scene을 iOS 13부터 지원하게 되면서 iOS 12까지의 AppDelegate와는 다르다.

같은 App을 동시에 여러개 켰다..!

각각의 App의 화면을 Scene이라고 일컫는다.

따라서 iOS 13부터는 Scene을 지원하게 되면서, 하나의 App을 여러개(다수의 인스턴스 / Scene)를 사용할 수 있는 것이다.

 

이전까지의 AppDelegate에서는 하나의 Scene만을 관리하게 설계되어 있었다.

하지만 위와 같은 iPad의 경우엔, 상황에 따라 여러 Scene을 허용해야 하는 경우가 있을 것이다. 그렇다면 여러 Scene을 AppDelegate에서 동시에 관리할 수 없지 않은가?

따라서 iOS 13부터는 SceneDelegate를 통해 Scene을 관리할 수 있다.

 

 

AppDelegate(~ iOS 12) vs SceneDelegate(iOS 13 ~)

 

12까지의 AppDelegate의 역할은 크게 2가지 였습니다.

Process LifeCycle, UI LifeCycle

 

 

13부터는 UI LifeCycle은 SceneDelegate가 처리합니다.

각각의 Scene마다 현재 가장 상단에 있는 VC, 내부에 UI Components가 각각의 상황에 따라 다를 것이다.

-> 그렇지 않으면 Scene을 사용할 의미가 없다고 생각함...

 

(이후에SceneDelegate에 대해서 좀 더 알아보도록 하겠다.)

 

 

ViewController의 수명주기 보러 가기

Local Notification

이전에 프로젝트를 진행하며, 사용자가 설정한 시각에 Push 알림을 진행한 경험이 있다. 그 당시에도 역시 프로젝트 기간으로 인해 자세히 공부하지 못하였기에, 이번 기회에 좀 더 자세히 알아보자

 

로컬 알림

  • 앱 내부에서 만든 특정 메시지를 iOS 알림센터를 통해 전달하는 방법
  • 앱이 종료되거나 백그라운드 상태일 때, 메세지를 전달할 수 있는 대표적인 방법
  • 알림은 iOS 스케줄러에 의해 발송되는데, 미리 메시지와 발송 시각을 구성해놓아야한다.-> 앱이 메모리에 살아있지 않아도 발송이 가능하다!
  • 만약 앱이 메모리에 살아있을 때, 어떠한 메시지를 발송하고 싶다면, 로컬 알림 보다는 다른 메세지 창을 이용하는 것이 효율적이다
    • 작업이 AppDelegate를 통해 작업이 이뤄지기 때문이다.
  • 다른 용도는 스케줄링이다 (CS에서의 스케줄링이 아닌 User의 시간을 관리해주는 스케줄링)
    • 아침에 일어날 때,  다들 알람을 맞춰놓죠? 그런 것을 생각하면 됩니다!

변화

이전(iOS 10 이전)에는 UILocalNotification을 사용하였습니다. 하지만 최근에는 Apple이 사용자 알림에 관한 모든 것을 전담 처리할 UserNotification 프레임워크를 제공하므로써 이를 사용합니다.

 

UserNotification 프레임워크

알림을 위한 여러가지 객체를 갖고 있으며, 내부에서는 UN이라는 접두어를 사용하여 객체 이름을 정의합니다.

 

import UserNotifications

 

객체

  1. UNMutableNotificationContent
    1. 알림에 필요한 메세지와 같은 속성을 담는 콘텐츠 역할
    2. 로컬 알림 타이틀, 서브 타이틀, 알림 메시지 설정 가능
    3. 앱 아이콘에 표시될 뱃지나 사운드 설정도 해당 객체를 통해 설정한다
  2. UNTimeIntervalNotificationTrigger
    1. 알림 발송 조건을 관리
    2. 발생 시각과 반복 여부를 설정 가능
    3. "몇 초 후" 단위로 설정한다. 하루 중 특정 시각에 맞추고 싶다면 UNCalendarNotificationTrigger를 사용한다
  3. UNNotificationRequest
    1. 위의 2가지를 설정한 후, 그것들을 모아서 전달하기 위한 알림 요청 객체를
  4. UNUserNotificationCenter
    1. 실제 발송을 담당
    2. 싱글턴 방식으로 동작한다 -> 객체 생성이 아닌 current()를 통해 정보에 접근 가능

 

Example

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        if #available(iOS 10.0, *) {
            let notiCenter = UNUserNotificationCenter.current()
            notiCenter.requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { didAllow, e in
            	if didAllow{
                	//사용자가 Allow
                } else{
                	//사용자가 Not Allow
                }
            })
        }

        return true
    }

 

사용자에게  승인을 받는 과정을 거쳐야 한다. 당연히 사용자가 허용하지 않으면 알림을 발송하더라도 메시지를 받을 수 없다.

 

또한, 승인을 굳이 App이 켜지는 동안 받을 필요는 없다. 하지만 대부분의 앱이 그런식으로 받고 있어서 여기다가 넣었다...

 

func sceneWillResignActive(_ scene: UIScene) {//알림 동의 여부를 확인
        print("WillResign")
        if #available(iOS 10.0, *){
            UNUserNotificationCenter.current().getNotificationSettings { settings in
                if settings.authorizationStatus == UNAuthorizationStatus.authorized{
                    let content = UNMutableNotificationContent()
                    content.badge = 1
                    content.title = "로컬 푸시"
                    content.subtitle = "서브 타이틀"
                    content.body = "바디바디바디받비ㅏ디바딥다비답디ㅏㅂ딥다비다비답다ㅣ"
                    content.sound = .default
                    content.userInfo = ["name": "tree"]
                    
                    //5초 후, 반복하지 않음
                    let trigger = UNTimeIntervalNotificationTrigger(timeInterval: 5, repeats: false)
                    
                    let request = UNNotificationRequest(identifier: "firstPush", content: content, trigger: trigger)
                    
                    //발송을 위한 센터에 추가
                    UNUserNotificationCenter.current().add(request)
                }else{
                    //사용자가 알림을 허용하지 않음
                    print("알림 허용 않음")
                }
            }
        }else{
            //사용자의 폰이 iOS 9 이하임
            print("9버전 이하")
        }
    }

아까 준비 코드는 AppDelegate에 넣어놓고 왜 이 코드는 SceneDelegate에 넣어?

-> 음... appDelegate에도 같은 수명주기 메소드가 존재한다. 넣고 실행을 해보면 왜 넣는지에 대해서는 이해할 것이다.

 

실행을 한 후에, Application을 Resign 즉 Background상태로 보내게 되면 메시지가 등록이 되고 5초 후에 센터가 스스로 메시지를 발송하여 정상적으로 동작한다.

 


SceneDelegate vs AppDelegate

WWDC 2019

그림과 같이 iOS 13버전 이전과 이후로 SceneDelegate가 다르다.

위의 그림에서는 AppDelegate가 Process 수명주기와 UI 수명주기 모두를 관리하였다.

하지만, 아래의 그림을 보면 AppDelegate에서는 Process 수명주기와 Session 수명주기를 관리하고,

SceneDelegate에서 UI 수명주기를 관리한다.

 

그렇다면 왜 SceneDelegate가 나왔는가? 그리고 역할을 구분하였는가?

 

Scene

UIKit는 UIWindowScene 객체를 사용하는 앱 UI의 각 인스턴스를 관리합니다. 
Scene에는 UI의 하나의 인스턴스를 나타내는 windows와 view controllers가 들어있습니다.
 또한 각 scene에 해당하는 UIWindowSceneDelegate 객체를 가지고 있고,
이 객체는 UIKit와 앱 간의 상호 작용을 조정하는 데 사용합니다.
Scene들은 같은 메모리와 앱 프로세스 공간을 공유하면서 서로 동시에 실행됩니다.
결과적으로 하나의 앱은 여러 scene과 scene delegate 객체를 동시에 활성화할 수 있습니다.
(Scenes - Apple Developer Document 참고)

 

해당의 이유로 UI 수명주기를 SceneDelegate에서 관리하므로써 App의 수명주기에 해당하는 메소드들은 SceneDelegate에서 사용할 수 있다.

 

 

+ Recent posts