2018-07-11 學(xué)習(xí)程序的執(zhí)行順序和UIViewController的生命周期

參考自這篇文章這篇對前文的整合

一.程序啟動執(zhí)行順序

1.程序的入口

main函數(shù),設(shè)置AppDelegate為函數(shù)的代理。

2.程序完成加載

-[AppDelegate application:didFinishLaunchingWithOptions:]

3.創(chuàng)建Window窗口

4.程序被激活

-[AppDelegate applicationDidBecomeActive:]

5.點擊Home鍵

首先,程序會取消激活狀態(tài):-[AppDelegate applicationWillResignActive:]

然后,程序進(jìn)入后臺:-[AppDelegate applicationDidEnterBackground:]

6.重新點擊進(jìn)入程序

首先,程序進(jìn)入前臺:-[AppDelegate applicationWillEnterForeground:]

然后,程序會被激活:-[AppDelegate applicationDidBecomeActive:]

與Android的生命周期有著異曲同工之妙,但也有些許區(qū)別,比如創(chuàng)建進(jìn)程之后,是加載\rightarrow激活的,沒有applicationWillEnterForeground

  1. 創(chuàng)建進(jìn)程

onCreate() / applicationDidFinishLaunching

  1. 進(jìn)入視野(沒獲取焦點)

onStart() / applicationWillEnterForeground

  1. 獲取焦點(可操作)

onResume() / applicationDidBecomeActive

  1. 失去焦點(還在視野內(nèi),不可操作)

onPause() / applicationWillResignActive

  1. 離開視野

onStop() / applicationDidEnterBackground

6.殺死程序

onDestroy() / applicationWillTerminate

2.在APPDelegate類實現(xiàn)的文件以及對應(yīng)操作

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOption{// Override point for customization after application launch.
    NSLog(@"didFinishLaunchingWithOptions");
    return YES;
}

/* 當(dāng)應(yīng)用程序從活動狀態(tài)(active)變到非活動狀態(tài)(inactive時被觸發(fā)調(diào)用, 這可能發(fā)生在一些臨時中斷下(例如:來電話、來短信)又或者程序退出時,他會先過渡到后臺然后terminate 使用這方法去暫停正在進(jìn)行的任務(wù),禁用計時器,節(jié)流OpenGL ES 幀率。在游戲中應(yīng)該在這個方法里面暫停游戲。 */
- (void)applicationWillResignActive:(UIApplication *)application { 
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
    NSLog(@"WillResignActive");
}

 /* 使用這種方法來釋放共享資源,保存用戶數(shù)據(jù),無效計時器,存儲足夠多的應(yīng)用程序狀態(tài)信息來恢復(fù)您的應(yīng)用程序的當(dāng)前狀態(tài),以防它終止丟失數(shù)據(jù)。 如果你的程序支持后臺運(yùn)行,那么當(dāng)用戶退出時不會調(diào)用applicationWillTerminate。 */
- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.      // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        NSLog(@"DidEnterBackground");
    }

 /* 先從后臺切換到非活動狀態(tài),然后進(jìn)入活動狀態(tài)。 */
- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
    NSLog(@"WillEnterForeground");
}

/* 重啟所有的任務(wù),不管是從非活動狀態(tài)還是剛啟動程序,還是后臺狀態(tài)。 */
- (void)applicationDidBecomeActive:(UIApplication *)application { 
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        NSLog(@"DidBecomeActive");
    }

/* 終止,game over */
- (void)applicationWillTerminate:(UIApplication *)application { 
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    NSLog(@"WillTerminate");
}

剛啟動時出現(xiàn)了兩個:


啟動

按下Home鍵又出現(xiàn)了兩個:


后臺

點回去又出現(xiàn)了兩個:


回到前臺

由此,可以得到以下生命周期圖:

活動和非活動

生命周期圖

對于每個階段的分析:

  • application: didFinishLaunchingWithOptions:程序首次已經(jīng)完成啟動時執(zhí)行,一般在這個函數(shù)里面創(chuàng)建Window對象,將程序內(nèi)容通過Window呈現(xiàn)給用戶。

  • applicationWillResignActive:程序?qū)⒁?code>Active狀態(tài)時調(diào)用,比如有電話進(jìn)來或者按下Home鍵,之后程序進(jìn)入后臺狀態(tài),對應(yīng)applicationWillEnterForeground方法。該函數(shù)主要執(zhí)行的操作有:
    a. 暫停正在執(zhí)行的任務(wù)
    b. 禁止計時器
    c. 減少OpenGL ES幀率
    d. 若為游戲則暫停游戲

  • applicationDidEnterBackground(已經(jīng)進(jìn)入后臺):對應(yīng)的是applicationDidBecomeActive(已經(jīng)變成前臺)。該方法用來:
    a. 釋放共享資源
    b. 保存用戶數(shù)據(jù)(寫到硬盤)
    c. 作廢計時器
    d. 保存足夠的程序狀態(tài)以便下次修復(fù)

  • applicationWillEnterForeground(即將進(jìn)入前臺):用來撤銷applicationWillResignActive(即將進(jìn)入后臺)做出的改變。

  • applicationDidBecomeActive(已經(jīng)進(jìn)入前臺):程序已經(jīng)變?yōu)?code>Active時調(diào)用,對應(yīng)applicationDidEnterBackground。若程序之前在后臺,則在此方法內(nèi)刷新用戶界面。

  • applicationWillTerminate:程序即將退出時調(diào)用,記得保存數(shù)據(jù),如applicationDidEnterBackground一樣。

二.UIViewController生命周期

之前在視頻器播放項目中遇到過關(guān)于ViewController的問題反饋,現(xiàn)在再把它拿出來:

首先看看單個viewController的生命周期:

  1. loadView:加載view 會多次調(diào)用并且會使viewWillLayoutSubviews、viewDidLayoutSubviews不再執(zhí)行
  2. viewDidLoadview加載完畢
  3. viewWillAppear:控制器的view將要顯示
  4. viewWillLayoutSubviews:控制器的view將要布局子控件
  5. viewDidLayoutSubviews:控制器的view布局子控件完成
    這期間系統(tǒng)可能會多次調(diào)用viewWillLayoutSubviews 、 viewDidLayoutSubviews 兩個方法
  6. viewDidAppear:控制器的view完全顯示
  7. viewWillDisappear:控制器的view即將消失的時候
  8. viewDidDisappear:控制器的view完全消失的時候

整個控制器生命周期:loadView-> viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear -> viewWillDisappear -> viewDidDisappear

  • viewDidLoad:當(dāng)程序第一次加載view時調(diào)用,以后都不會用到,而viewDidAppear是每當(dāng)切換到view時就調(diào)用。

  • viewWillAppear:系統(tǒng)在載入所有的數(shù)據(jù)之后,將會在屏幕上顯示視圖,這時候會先調(diào)用這個方法,通常我們會在這個方法對即將顯示的視圖做進(jìn)一步的設(shè)置,如:設(shè)置設(shè)備不同方向的時候該如何顯示;設(shè)置狀態(tài)欄方向、設(shè)置視圖顯示樣式等等。

  • viewWillLayoutSubviews :在 viewWillAppear 之后, viewDidAppear 之前執(zhí)行,view即將布局其subViews,比如viewbounds發(fā)生了改變(狀態(tài)欄從不顯示到顯示、視圖方向發(fā)生變化),在調(diào)整之前要做的工作可以放在這個方法實現(xiàn)。

注意:這個方法會被調(diào)用多次,如果在此創(chuàng)建視圖,可能會創(chuàng)建多個,而且這個方法中執(zhí)行耗時操作依然會造成跳轉(zhuǎn)卡頓的問題。

  • viewDidLayoutSubviews:放置調(diào)整之后的工作

  • didReceiveMemoryWarning:在內(nèi)存足夠的情況下,APP的視圖通常會一直保存在內(nèi)存中,但如果內(nèi)存不夠,一些沒有正在顯示的View Controller就會收到內(nèi)存不足的警告,然后就會釋放自己擁有的視圖,以達(dá)到釋放內(nèi)存的目的。但是系統(tǒng)只會釋放內(nèi)存,并不會釋放對象的所有權(quán),所以通常將不需要顯示在內(nèi)存中保留的對象釋放它的所有權(quán),將其指針置為nil。

下面寫個程序來試試:

//視圖控制器中的視圖加載完成,viewController自帶的view加載完成
- (void)viewDidLoad {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewDidLoad];
    
    UIButton *button = [[UIButton alloc] initWithFrame: CGRectMake(self.view.frame.size.width / 2 - 100,
                                                                   self.view.frame.size.height / 2 - 30,
                                                                   100,
                                                                   30)];
    [self.view addSubview: button];
    [button setTitle: @"Click" forState: UIControlStateNormal];
    [button setBackgroundColor: [UIColor blueColor]];
    [button addTarget: self action: @selector(buttonClicked:) forControlEvents: UIControlEventTouchUpInside];
    
    
    // Do any additional setup after loading the view.
}

- (void) buttonClicked: (UIButton *) sender {
    AnotherViewController *anotherViewController = [[AnotherViewController alloc] init];
    [self.navigationController pushViewController: anotherViewController animated: YES];
    
}
//出現(xiàn)內(nèi)存警告  //模擬內(nèi)存警告:點擊模擬器->hardware-> Simulate Memory Warning
- (void)didReceiveMemoryWarning {
    NSLog(@"One--%s", __FUNCTION__);
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

//視圖將要出現(xiàn)
- (void)viewWillAppear:(BOOL)animated {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewWillAppear:animated];
}

//將要布局子視圖
- (void) viewWillLayoutSubviews {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewWillLayoutSubviews];
}

//布局子視圖完畢
- (void)viewDidLayoutSubviews {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewDidLayoutSubviews];
}

//視圖已經(jīng)出現(xiàn)
- (void)viewDidAppear:(BOOL)animated {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewDidAppear:animated];
}

//視圖將要消失 //雙擊Home鍵,向上推出程序執(zhí)行該函數(shù)
- (void)viewWillDisappear:(BOOL)animated {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewWillDisappear:animated];
}

//視圖已經(jīng)消失
- (void)viewDidDisappear:(BOOL)animated {
    NSLog(@"One--%s", __FUNCTION__);
    [super viewDidDisappear:animated];
}

下面來演示一下各種情況各個步驟的執(zhí)行順序:

1.啟動

viewDidLoad -> viewWillAppear -> viewWillLayoutSubviews -> viewDidLayoutSubviews -> viewDidAppear

2.模擬Memory Warning

點擊模擬器->hardware-> Simulate Memory

3.跳轉(zhuǎn)到Controller2

可以看到,兩個View Controller的生命周期是很符合我們設(shè)想的邏輯的,2加載完畢后告知1準(zhǔn)備消失,2準(zhǔn)備出現(xiàn),然后2可以進(jìn)行子布局的布置,布置完畢后,1先消失,隨后2出現(xiàn)。

2--viewDidLoad -> 1--viewWillDisappear -> 2--viewWillAppear -> 2--viewWillLayoutSubviews -> 2--viewDidLayoutSubviews -> 1--viewDidDisappear -> 2--viewDidAppear

4.Controller2出棧

出棧的過程其實就是免去了加載布局和布置子布局,因此他的邏輯順序同樣是消失的先執(zhí)行,出現(xiàn)的后執(zhí)行,如下所示:

2--viewWillDisappear -> 1--viewWillAppear -> 2--viewDidDisappear -> 1--viewDidAppear

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容