UIViewController生命週期html
UIViewControl是IOS程序中的一個重要組成部分,扮演者一個大管家的身份,管理着程序中的衆多視圖,今天看看了官方文檔並作了以下一些簡單的記錄:ios
什麼時候加載view,加載的原則是什麼,視圖什麼時候消失等問題,文檔中講的都很詳細。安全
Controller的view最好在須要顯示時再去加載,而且在系統發出內存警告時釋放比必要的view及相關的數據對象。app
1、UIViewController的初始化less
初始化時會根據須要調用init,initWithCoder等相關函數,這個時候咱們能夠作一下簡單的初始化操做,創建ViewController中須要使用的數據模型等,不建議在初始化階段就直接建立view及其餘與顯示有關的對象(應該放到loadView的時候去建立,或者採用懶加載的方法建立)。ide
咱們都知道ViewController能夠經過代碼和xib兩種方式建立,這兩種方式的初始化流程也不盡相同。函數
1)使用xib建立的VCpost
xib其實最終是會把咱們的設置保存成一個數據集,當須要初始化構建VC的時候,回去讀取記錄的數據集,而後幫咱們動態的建立VC,所以能夠想象它在初始化時會先去找看是否實現initWithCoder方法,若是該類實現了該方法,就直接調用initWithCoder方法建立對象,若是沒有實現的話就調用init方法。調用完初始化方法之後緊接着會調用awakeFromNib方法,在這個方法裏面咱們能夠作進一步的初始化操做。ui
2)使用代碼建立VCthis
使用代碼建立時,咱們根據須要手動的建立VC中的數據,若是本身定製VC時,還須要在init中調用[super init]。
2、UIViewController中View的load和unload
前面講了不建議在VC初始化的時候就建立view及其餘與顯示相關的代碼,官方文檔建議將View的初始化操做放到loadView的時候再作,當VC接到內存告警時會調用didRecieveMemoryWarning這個時候咱們就要作出響應,釋放暫時不須要的對象。若是無視這個警告,系統內存不夠用時會會繼續發送,若是還得不處處理就會強制退出程序。下面看具體的loadView和unloadView時候都會作什麼操做。
1)Load週期
當須要顯示或者訪問view屬性時,view沒有建立的話,VC就會調用loadView方法,在這個時候會建立一個view並將其賦給VC.view屬性。緊接着就會調用VC的viewDidLoad方法,這個時候VC.view保證是有值的,能夠作進一步的初始化操做,例如添加一些subview。注意:定製VC時,若是覆蓋loadView方法,不須要調用[super loadView]方法。
2)Unload週期
當app收到內存警告的時候,會調用每個VC的didRecieveMemoryWarning方法,咱們須要作出響應,釋放程序中暫時不須要的資源。一般都會重寫該方法,重寫時候須要調用super的該方法。若是檢測到當前VC的view能夠被安全釋放的話,就會調用viewWillUnload方法,這個咱們必需要重視,由於當VC的view消失時候它的subviews可能會被一塊兒釋放,咱們須要根據具體狀況作一些記錄,以保證下次可以正確建立,同時不出現內存泄漏。調用viewWillUnload之後,會將VC.view屬性設置成nil,而後在調用viewDidUnload方法,這個時候咱們能夠釋放那些強引用的對象。
When memory available to the app runs low, all view controllers are automatically notified by the system. This allows the view controller to purge caches and other objects that can be easily recreated later when memory is more plentiful. The exact behavior varies depending on which version of iOS your app is running on, and this has implications for your view controller design.
Carefully managing the resources associated with your view controllers is critical to making your app run efficiently. You should also prefer lazy allocation; objects that are expensive to create or maintain should be allocated later and only when needed. For this reason, your view controllers should separate objects needed throughout the lifetime of the view controller from objects that are only necessary some of the time. When your view controller receives a low-memory warning, it should be prepared to reduce its memory usage if it is not visible onscreen.
When a view controller is first instantiated, it creates or loads objects it needs through its lifetime. It should not create its view hierarchy or objects associated with displaying content. It should focus on data objects and objects needed to implement its critical behaviors.
When you create a view controller in a storyboard, the attributes you configure in Interface Builder are serialized into an archive. Later, when the view controller is instantiated, this archive is loaded into memory and processed. The result is a set of objects whose attributes match those you set in Interface Builder. The archive is loaded by calling the view controller’s initWithCoder:
method. Then, the awakeFromNib
method is called on any object that implements that method. You use this method to perform any configuration steps that require other objects to already be instantiated.
For more on archiving and archiving, see Archives and Serializations Programming Guide.
If a view controller allocates its resources programmatically, create a custom initialization method that is specific to your view controller. This method should call the super class’s init
method and then perform any class specific initialization.
In general, do not write complex initialization methods. Instead, implement a simple initialization method and then provide properties for clients of your view controller to configure its behaviors.
Whenever some part of your app asks the view controller for its view object and that object is not currently in memory, the view controller loads the view hierarchy into memory and stores it in its view
property for future reference. The steps that occur during the load cycle are:
The view controller calls its loadView
method. The default implementation of the loadView
method does one of two things:
If the view controller is associated with a storyboard, it loads the views from the storyboard.
If the view controller is not associated with a storyboard, an empty UIView
object is created and assigned to the view
property.
The view controller calls its viewDidLoad
method, which enables your subclass to perform any additional load-time tasks.
Figure 4-1 shows a visual representation of the load cycle, including several of the methods that are called. Your app can override both theloadView
and the viewDidLoad
methods as needed to facilitate the behavior you want for your view controller. For example, if your app does not use storyboards but you want additional views to be added to the view hierarchy, you override the loadView
method to instantiate these views programatically.
Most view controllers load their view from an associated storyboard. The advantage of using storyboards is that they allow you to lay out and configure your views graphically, making it easier and faster to adjust your layout. You can iterate quickly through different versions of your user interface to end up with a polished and refined design.
Interface Builder is part of Xcode and provides an intuitive way to create and configure the views for your view controllers. Using Interface Builder, you assemble views and controls by manipulating them directly, dragging them into the workspace, positioning them, sizing them, and modifying their attributes using an inspector window. The results are then saved in a storyboard file, which stores the collection of objects you assembled along with information about all the customizations you made.
To help you layout the contents of your view properly, Interface Builder provides controls that let you specify whether the view has a navigation bar, a toolbar, or other objects that might affect the position of your custom content. If the controller is connected to container controllers in the storyboard, it can infer these settings from the container, making it easier to see exactly how it should appear at runtime.
Using Interface Builder, you create connections between the views in your interface and your view controller.
Listing 4-1 shows the declaration of a custom MyViewController
class’s two custom outlets (designated by the IBOutlet
keyword) and a single action method (designated by the IBAction
return type). The declarations are made in a category inside the implementation file. The outlets store references to a button and a text field in the storyboard, while the action method responds to taps in the button.
Custom view controller class declaration
@interface MyViewController() |
@property (nonatomic) IBOutlet id myButton; |
@property (nonatomic) IBOutlet id myTextField; |
|
- (IBAction)myAction:(id)sender; |
@end |
Figure 4-2 shows the connections you would create among the objects in such a MyViewController
class.
When the previously configured MyViewController
class is created and presented, the view controller infrastructure automatically loads the views from the storyboard and reconfigures any outlets or actions. Thus, by the time the view is presented to the user, the outlets and actions of your view controller are set and ready to be used. This ability to bridge between your runtime code and your design-time resource files is one of the things that makes storyboards so powerful.
If you prefer to create views programmatically, instead of using a storyboard, you do so by overriding your view controller’s loadView
method. Your implementation of this method should do the following:
Create a root view object.
The root view contains all other views associated with your view controller. You typically define the frame for this view to match the size of the app window, which itself should fill the screen. However, the frame is adjusted based on how your view controller is displayed. See「Resizing the View Controller’s Views.」
You can use a generic UIView
object, a custom view you define, or any other view that can scale to fill the screen.
Create additional subviews and add them to the root view.
For each view, you should:
Create and initialize the view.
Add the view to a parent view using the addSubview:
method.
If you are using auto layout, assign sufficient constraints to each of the views you just created to control the position and size of your views. Otherwise, implement the viewWillLayoutSubviews
and viewDidLayoutSubviews
methods to adjust the frames of the subviews in the view hierarchy. See 「Resizing the View Controller’s Views.」
Assign the root view to the view
property of your view controller.
Listing 4-2 shows an example implementation of the loadView
method. This method creates a pair of custom views in a view hierarchy and assigns them to the view controller.
Creating views programmatically
- (void)loadView |
{ |
CGRect applicationFrame = [[UIScreen mainScreen] applicationFrame]; |
UIView *contentView = [[UIView alloc] initWithFrame:applicationFrame]; |
contentView.backgroundColor = [UIColor blackColor]; |
self.view = contentView; |
|
levelView = [[LevelView alloc] initWithFrame:applicationFrame viewController:self]; |
[self.view addSubview:levelView]; |
} |
Note: When overriding the loadView
method to create your views programmatically, you should not call super
. Doing so initiates the default view-loading behavior and usually just wastes CPU cycles. Your own implementation of the loadView
method should do all the work that is needed to create a root view and subviews for your view controller. For more information on the view loading process, see 「A View Controller Instantiates Its View Hierarchy When Its View is Accessed.」
When it comes to view controllers and memory management, there are two issues to consider:
How to allocate memory efficiently
When and how to release memory
Although some aspects of memory allocation are strictly yours to decide, the UIViewController
class provides some methods that usually have some connection to memory management tasks. Table 4-1 lists the places in your view controller object where you are likely to allocate or deallocate memory, along with information about what you should be doing in each place.
Task |
Methods |
Discussion |
---|---|---|
Allocating critical data structures required by your view controller |
Initialization methods |
Your custom initialization method (whether it is named |
Creating your view objects |
Overriding the |
|
Creating custom objects |
Custom properties and methods |
Although you are free to use other designs, consider using a pattern similar the |
Allocating or loading data to be displayed in your view |
Data objects are typically provided by configuring your view controller’s properties. Any additional data objects your view controller wants to create should be done by overriding the |
|
Responding to low-memory notifications |
Use this method to deallocate all noncritical objects associated with your view controller. On iOS 6, you can also use this method to release references to view objects. |
|
Releasing critical data structures required by your view controller |
Override this method only to perform any last-minute cleanup of your view controller class. Objects stored in instance variables and properties are automatically released; you do not need to release them explicitly. |
The default behavior for a view controller is to load its view hierarchy when the view
property is first accessed and thereafter keep it in memory until the view controller is disposed of. The memory used by a view to draw itself onscreen is potentially quite large. However, the system automatically releases these expensive resources when the view is not attached to a window. The remaining memory used by most views is small enough that it is not worth it for the system to automatically purge and recreate the view hierarchy.
You can explicitly release the view hierarchy if that additional memory is necessary for your app. Listing 4-3 overrides thedidReceiveMemoryWarning
method to accomplish this. First, is calls the superclass’s implementation to get any required default behavior. Then, it cleans up the view controller’s resources. Finally, it tests to see if the view controller’s view is not onscreen. If the view is associated with a window, then it cleans up any of the view controller’s strong references to the view and its subviews. If the views stored data that needs to be recreated, the implementation of this method should save that data before releasing any of the references to those views.
Releasing the views of a view controller not visible on screen
- (void)didReceiveMemoryWarning |
{ |
[super didReceiveMemoryWarning]; |
// Add code to clean up any of your own resources that are no longer necessary. |
if ([self.view window] == nil) |
{ |
// Add code to preserve data stored in the views that might be |
// needed later. |
|
// Add code to clean up other strong references to the view in |
// the view hierarchy. |
self.view = nil; |
} |
The next time the view
property is accessed, the view is reloaded exactly as it was the first time.
In earlier versions of iOS, the system automatically attempts to unload a view controller’s views when memory is low. The steps that occur during the unload cycle are as follows:
The app receives a low-memory warning from the system.
Each view controller calls its didReceiveMemoryWarning
method. If you override this method, you should use it to release any memory or objects that your view controller object no longer needs. You must call super
at some point in your implementation to ensure that the default implementation runs. On iOS 5 and earlier, the default implementation attempts to release the view. On iOS 6 and later, the default implementation exits.
If the view cannot be safely released (for example, it is visible onscreen), the default implementation exits.
The view controller calls its viewWillUnload
method. A subclass typically overrides this method when it needs to save any view properties before the views are destroyed.
It sets its view
property to nil
.
The view controller calls its viewDidUnload
method. A subclass typically overrides this method to release any strong references it has to those views.
Figure 4-3 shows a visual representation of the unload cycle for a view controller.
Unloading a view from memory