iOS Develop – app View Lifecycle測試 (2)

原本(自)以為關於 app 生命週期,透過上次測試就已經大概掌握了,直到最近某個專案練習到一半才發現,原來在不同情況下,viewWillAppear、viewDidAppear、viewWillDisappear、viewDidDisappear 的執行時機與次數,還有另一種模式。

原因在於,上一個文章裡面的範例,我們是在兩個 view 之間移動,所以當我們從第一個 view 轉換到第二個 view 的時候,理所當然第一個 view 會需要經歷 viewWillDisappear、viewDidDisappear ,而我們從第二個 view 回到第一個 view的時候,第一個 view 會需要再一次經歷 viewWillAppear、viewDidAppear。

但是,巴特,西咖西…….,如果我們是按下 home 鍵退出 app 再進入呢?

我一直都以為,按下 home 鍵之後,會執行 viewWillDisappear、viewDidDisappear ,然後從 background 叫回 app之後,會再執行 viewWillAppear、viewDidAppear,就跟切換 view 一樣。

應該有很多人跟我想的一樣吧?

應該吧?(心虛)

anyway,如果你知道答案,就可以不用往下看了,如果你也跟我一樣誤解或沒有弄清楚,那我一樣替大家實作一次來試驗結果是如何。

除此之外,另一件讓我頭痛很久的問題是:tableView 到底是哪一個步驟開始建立的?

會有這個問題,是因為我目前在練習的專案中,有一個步驟是:

  1. 從雲端下載資料
  2. 將資料建立成 Array
  3. 讓 Array 成為 tableView cell 的內容

這中間會有一個時間差,也就是在還沒有下載完資料的時候,如果已經建立好 tableView,那當下的 tableView 就會空白一片在那邊,除非按下 home 鍵出去再進來,或是跳到別的 view 再回來 tableView,才會出現內容。

這個問題後來是解決了,而且跟 「tableView 到底何時建立」這件事沒啥太大關聯,不過我也在這次的實作範例中建立了 tableView,大家就順便看一下到底 tableView 在 app 運作的背後程序是怎樣吧。

程式碼:

AppDelegate.swift:

  • 這邊我們就簡單得在每一個階段裡面 print 出該 func 的名字,另外我加上了編號,這樣可以容易一目瞭然。


import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
print("1 didFinishLaunchingWithOptions 開始lunching")
return true
}
func applicationWillResignActive(_ application: UIApplication) {
print("2 applicationWillResignActive 將結束活動")
}
func applicationDidEnterBackground(_ application: UIApplication) {
print("3 applicationDidEnterBackground 進入後台")
}
func applicationWillEnterForeground(_ application: UIApplication) {
print("4 applicationWillEnterForeground 進入前端")
}
func applicationDidBecomeActive(_ application: UIApplication) {
print("5 applicationDidBecomeActive 已經活動")
}
func applicationWillTerminate(_ application: UIApplication) {
print("6 applicationWillTerminate 掰掰")
}
}

ViewController.swift:

  • 這邊也是在每一個 func 裡面加入 print ,讓運行到它的時候可以秀出來,我們就會知道完整的流程到底是怎麼跑的。
  • 這邊用的編號是大寫英文字母。
  • 這邊也加入了 tableView 以及需要遵循的 protocol。
  • 我設了 1 個 section,3 個存放格,內容都是 xdasu。
  • 注意如果該 func 有 return 東西的話,print 要放在 return 前面,否則將不會執行該次 print ,因為 func 本身認為他的工作已經完成了。xcode 會給你黃色提醒,但仍然會正常運作,所以你不會發現該次 print 沒有出來。


import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
@IBOutlet weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
print("A viewDidLoad")
}
override func viewWillAppear(_ animated: Bool) {
print("B viewWillAppear")
}
override func viewDidAppear(_ animated: Bool) {
print("C viewDidAppear")
}
override func viewWillDisappear(_ animated: Bool) {
print("D viewWillDisappear")
}
override func viewDidDisappear(_ animated: Bool) {
print("E viewDidDisappear")
}
func numberOfSections(in tableView: UITableView) -> Int {
print("numberOfSections 幾個section")
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("numberOfRowsInSection 每個section有幾個row")
return 3
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
cell.textLabel?.text = "xdasu"
print("cellForRowAt 建立cell內容")
return cell
}

以下是執行結果:

app lifecycle 生命週期

S__4841540

幾個重點:

  • 按下 home 鍵後,並不會執行 viewWillDisappear、viewDidDisappear 。
  • 回到 app 後,也不會再次執行 viewWillDisappear、viewDidDisappear。
  • 會再次執行上述四個 func 的時機,只有在 app 開啟當下,內部轉換 view 的狀況。
  • tableView 建立的時機,是在 viewWillAppear 之後,viewDidAppear 之前。
  • 但這是我已經設定好顯示內容的情況,如果是從雲端下載資料,再放到 cell 裡面的話,再資料下載完之前,其實還會重複執行好幾次 tableView 的幾個 func ,詳細次數我沒有去數,大家可以自己玩玩看。

補充一個我看到的資料(大陸網友的說法),其實在遠古時代 iOS 4.0 之前,退出跟進入 app 是會執行 viewWillDisappear、viewDidDisappear、viewWillDisappear、viewDidDisappear 的,只是後來 apple 把它改掉了。

可能有些資深的工程師沒有注意到這一點,就會告訴大家,「 viewDidLoad 裡面的東西只會執行一次,其他的 func 裡面都會在你每次重新顯示 view 之前再做一次。」

基本上這句話,沒有完全對錯,重點在於,目前的狀況是,如果是按 home 鍵退出 app ,再進入 view,是不會執行 viewWillAppear、viewDidAppear、viewWillDisappear、viewDidDisappear ,所以你寫在這幾個 func 裡面的東西,也「有可能」只會被執行一次。

以上,希望這個實作範例讓大家對 app 執行程序有更近一步的了解,如果要知道在兩個 view 之間轉換,會是怎樣的情況,請看我的另一篇文章:iOS Develop – app Lifecycle測試 (1)

專案檔案下載:

https://www.dropbox.com/sh/s7ae9umh2ic6z2o/AAD13OX2d1mqx97FNf0_4JBqa?dl=0

iOS Develop – app View Lifecycle測試 (2) 有 “ 1 則迴響 ”

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s