stack.jpg
寫這篇的起因是這樣的,朋友小朱寫了個控制器 modal 出來,里面用到了 NSTimer 然后他想 dealloc 的時候關閉 timer(由關閉通知監聽想到) ,可是就發現該控制器 dissmiss 的時候代碼根本不走這里,出現了內存泄露。我建議他在viewWillDisappear之前需要把 NSTimer 銷毀了就可以了。再檢查下有沒有使用 Block 引用實例變量即可解決。可是這讓我想到了個問題,控制器跳轉的兩種方式的區別,好像并不能一下說的很清楚。
所以,首先我來談談 push 的管理方式。
NavigationController
- 一種最常見的情況 A 控制器上有個按鈕 push 到 B 控制器 它上又有個按鈕 push C 控制器 這里的內部機制是這樣的:
1.1 每個 NavigationController 都會對應一個 棧 來管理其子控制器,每 push 一個進來就壓棧(先進后出),放到棧頂。如下圖所示:
NavigationControllers.png
1.2 一旦有控制器進棧,可以簡單的理解為:就把這個控制器所對應的 View 創建出來,放到 NavigationController's View 上,若不是棧頂控制器的話,則把之前 NavigationController's View 移除(注意并沒有銷毀),再添加。如下圖所示:
PushViewController.png
現在就可以得出一個結論:
結論一:顯示在導航欄控制器的 View 永遠是棧頂控制器的 View。
1.3 我們再來看從 C控制器 返回到 A控制器,每返回一個就出棧一個,然后把其控制器銷毀。如下圖所示:
popViewController.png
從上面一系列的分析來看,則可以發現,一個導航控制器對應一個導航條,即多個子控制器共用一個導航條。
結論二:導航控控制條的內容由棧頂控制器決定(navigationItem)
Modal
2.為了搞清楚 Modal 的原理,我覺得自己擼一個就差不多了。這里給一個我做的過程:
2.1 把控制器的 View 加到 window 上;
2.2 使用 transform 向下平移一個屏幕高度,再清空 transform 完成動畫。
CustomModal.png
2.3 由于控制器的創建都是在函數內部完成的,所以函數執行完畢后就內存就回收了。所以如果該控制器還有操作的話,就會 EXC_BAD_ACCESS 所以我要添加一個屬性來強引用 ModalVC。
所以就發現 Modal 出的控制器是需要被強引用的,通過看文檔也可以發現 Modal 出的控制器會被當前控制器的 presentViewController 保存(強引用)。