混淆系列:App 的生命週期「App Life Cycle」

Y.H.H
在程式與旅行的路上
10 min readDec 6, 2020

iOS 系列#1

Photo credit: Tyler Lastovich on Unsplash

初學 iOS App 的時候經常聽到生命週期,也常常會是 “APP 101” 課程中的第一課。但生命週期其實可以分為兩類,一是「App 生命週期」、二是「view controller 生命週期」,如果稍微不注意一點就可能會造成溝通上的誤會哦。本輯的混淆系列首先會探討「App 生命週期」。

The App’s Life Cycle

Respond to system notifications when your app is in the foreground or background, and handle other significant system-related events. — by APPLE

每一個 App 都有屬於自己的生命週期,簡單來說當使用者點了 App、開啟了之後又返回桌面、切換到不同的 App、或是直接關閉···等等的這些行為都是 App 生命週期的一部分。

圖 1:App’s life cycle from APPLE

從官方的範例中我們可以了解到將生命週期分為五種狀態:

Not running

本身有兩種模式:一是 App 未被點擊開啟;二是 App 被使用者或是系統關閉,兩種模式都會處在這種狀態。

Inactive

當使用者點擊 App 後會進入到此模式。這時候雖然 App 已被啟動,但還是在初始化的階段,任何的點擊行為、或是發送請求等動作都無法使用。舉個例子:很多 App 在點開時會有一個過渡畫面、動畫、進度條等,這些都是 App 處在 Inactive 的階段,這個階段其實是非常短暫的。

Active

顧名思義就是 App 已將所有 UI 準備就緒,可以開始使用 App 了。處在這個階段的 App 沒有其他的受限條件,且必須能正常的使用。例如:登入、按下按鈕送出、顯示資資料···等。

Background

本身也有兩種模式:一是使用者直接將 App 關閉,這時會將 App 處在 Background 階段一陣子,之後就轉移到 Suspended 狀態。
第二則是使用者只是將 App 放到背景中;例如按下 Home 鍵、切換不同的 App。此時在這種階段的 App 仍可以被系統呼叫,進行一些像是下載、背景定位、或是通知等行為,但由於已在背景中,這時的 App 應盡最大化地降低它的工作量。

Suspended

當 App 進入此狀態,就不能再執行任何的程式碼,但它仍然在記憶體中保有一塊位置。當下一次使用者重新打開 App 時,它就會重新回到 Background 狀態、再回到 Inactive、最後回到 Active ,讓它繼續被使用。

圖 2:iOS 13 版本以前的生命週期圖。Photo credit:APPLE

圖 2 我們以圖像呈現方式快速了解 App 生命週期。那麼是誰來控制 App 的生命週期呢?這邊就要請到「AppDelegate.swift」,這個檔案我們一定不陌生,在我們建立 project 時都會有這麼的一個檔案。

AppDelegate.swift

The AppDelegate class conforms to the UIApplicationDelegate protocol, which defines methods that serve as hooks into the different events in the app’s life cycle. — by APPLE

iOS 版本 13 以前,AppDelegate 是一個 App 中的核心,它可處理初始化、各種生命週期狀態間的轉換、甚至是一些較為複雜的事件。

圖 3

從圖 3 我們點開 AppDelegate 的 class 查看,只剩下 3 個函式:

(_:didFinishLaunchingWithOptions:)

當 App 完成系統初始化的動作時,第一時間會呼叫此函式(注意:此時的 App 尚未進入前台模式,亦還不能使用),此函式會處理一些你寫的 code,例如:

Thread.sleep (time interval: ) //將執行緒暫緩幾秒後再進行動作

此外,當 App 進入到背景狀態時,再切回到原本的 App 中是不會呼叫該函式。

(_:configurationForConnecting:options:)

當建立一個新的畫面時會呼叫此函式。當我們什麼都沒有設置的時候,Xcode 會自動在 Info.plist 中生成一個默認的檔案,名為「Default Configuration」並保留在 plist 中讓使用者可以找到:

圖 4:打開 Xcode 到 plist 我們就能找到系統幫我們生成的 scene

(_:didDiscardSceneSessions:)

在 iPadOS 中使用。當使用者切換畫面時(例如關閉程式等)會呼叫此函式。使用此函式可有效的釋放 App 的資源。

SceneDelegate.swift

Your scene delegate is responsible for handling UI-level components during your app’s life cycle. These methods will be called for all scenes that your app has created. — by APPLE

iOS 版本 13之後,將 AppDelegate 大量的生命週期控制權交給了「SceneDelegate」。而它也包含了許多函式供我們使用:

圖 5:iOS 版本 13 之後,生命週期有了些許變化。Photo credit:APPLE

(_:willConnectTo:options:)

當 App 啟動後會第一時間呼叫此函式。例如使用「SwiftUI」來建立畫面的話,該函式會幫你建立「ContentView」;假如使用「Storyboard」建立畫面,則會自動生成並加入到畫面中。

sceneWillEnterForeground(_:)

當畫面連結創建好之後,緊接著會來到此函式。簡單扼要的來講就是準備將畫面呈現給使用者看,讓 App 準備進入到「Active」狀態中。這裡也包含了兩種模式:一是第一次開啟 App,二則是從背景切換回到當前的 App。

sceneDidBecomeActive(_:)

接下來,Scene 則會進入到此函式,也就是所謂的「Active」狀態,使該 App 能正常使用。倘若使用者忽略來電事件、系統通知事件,則會再次進入到 foreground 的 Active 狀態。

sceneWillResignActive(_:)

當 App 切換到背景或是被關閉時,會呼叫此函式,並進入到 Inactive 狀態。假如使用者在當前的 App 收到來電通知、系統通知等突發事件,畫面就會呼叫。

sceneDidEnterBackground(_:)

在呼叫完 sceneWillResignActive(_:) 後,就會呼叫此函式。當 App 正式進入到背景或關閉時,這時候可運用此函式來進行一些使用者的活動軌跡。例如:保存使用者的資訊、其他數據、釋放共用資源 / 記憶體···等,都可以寫在這個函式中。

sceneDidDisconnect(_:)

最後則是在 App 關閉後,iOS 系統會判斷是否要要儲存資料、釋放記憶體、資源時呼叫的函式。簡單來說會對應到 Inactive 或是 Suspended 的狀態。

實作顯示

列完上述之後還是覺得沒有頭緒嗎?我們可以直接開啟 Xcode,在「AppDelegate.swift」與「SceneDelegate」中每一個函式中直接 print 出 App 的生命週期!

print("Application did finish launching")print("Scene will connect to session")print("Scene did disconnect to session")print("Scene did become active")print("Scene will resign active")print("Scene will enter foreground")print("Scene did enter background")

之後開啟模擬器,我們便能清楚知道 App 的生命週期咯。

開啟 App 並準備畫面,進入到 Active 狀態(圖 6)

圖 6

將 App 切換到背景程式(圖 7)

圖 7

將 App 切換回前台(圖 8)

圖 8

將 App 完全關閉(圖 9)

圖 9

本輯混淆系列完整列出 App 生命週期,以後就不再會有不清楚的狀況咯,下輯我們將探討「view controller 的生命週期」。

混淆系列

--

--

Y.H.H
在程式與旅行的路上

If you walk the footsteps of a stranger, you’ll learn things you never knew you never knew.