溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

IOS視圖控制器導(dǎo)航及生命周期研究Demo

發(fā)布時間:2020-09-16 14:18:35 來源:網(wǎng)絡(luò) 閱讀:1282 作者:jackyBLF 欄目:移動開發(fā)

1、背景:

2014年4月份第一次接觸IOS端開發(fā),為某銀行開發(fā)一款金融app。
在開發(fā)的最后階段,加入了需要從任意一個頁面直接返回主頁的功能。
悲催的是,當時沒有使用UINavigationController進行導(dǎo)航管理,而是使用了IOS中的模態(tài)跳轉(zhuǎn)方式(presentViewController/dismissViewControllerAnimated).

因此需要找的一種方法進行,實現(xiàn)如下方式的導(dǎo)航跳轉(zhuǎn):

已知: 頁面a→頁面b→頁面c
求解: 頁面c直接跳回到頁面a,并且要求不能有內(nèi)存泄露,循環(huán)依賴等

2、解題思考:

面對上面的需求,最簡單的方式是將所有控制器都改成UINavigationController,并且利用pushViewController / popToViewController/ popToRootViewControllerAnimated 等方法進行完美解題。但是當時項目的頁面將近100個,分成三大模塊,需要大規(guī)模修改設(shè)計頁面以及調(diào)整大量代碼,這并不是一個現(xiàn)實的解決方案,不到萬不得已,不能采取如此低劣手段!

我們需要一個滿足如下條件的解決方案:

1) 對于已經(jīng)在InterfaceBuilder中完成的頁面,不做任何修改
2) 盡量少的修改代碼,因為很多代碼已經(jīng)經(jīng)過測試中心測試過,如果修改,需要全部重新測試,時間來不及。

當時通過兩天的研究,深入的了解了IOS中的跳轉(zhuǎn)流程和生命周期后,找到了一個相對完美的解決方案,能夠滿足上面提到的要求。通過一個Demo,來和大家一起分享。

3、解題流程:

1) 為了減少代碼的修改,增加一個基類。
@interface BaseViewController : UIViewController

//防止controller循環(huán)引用,使用weak引用方式
@property(nonatomic,weak) BaseViewController* parentController;

//為了能夠了解某個頁面控制器生命周期相關(guān)信息,給該控制器取個名字
@property(nonatomic,copy)   NSString*   ctrlName;

//關(guān)鍵的函數(shù),進行頁面c-->跳轉(zhuǎn)到主頁
-(void) doDismiss;

@end
2) 為了更好的了解IOS中ViewController的生命周期,我們在基類中輸出相關(guān)信息來了解生命周期相關(guān)信息。
@implementation BaseViewController

-(id) init
{
    self.ctrlName = @"";
    self.parentController = nil;
    return [super init];
}

- (void)viewDidLoad
{
    NSLog(@"%@ invoke viewDidLoad",self.ctrlName);
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

-(void)viewWillAppear:(BOOL)animated
{
    NSLog(@"%@ invoke viewWillAppear",self.ctrlName);
    [super viewWillAppear:animated];
}

-(void)viewDidAppear:(BOOL)animated
{
    NSLog(@"%@ invoke viewDidAppear",self.ctrlName);
    [super viewDidAppear:animated];
}

-(void) viewWillDisappear:(BOOL)animated
{
    NSLog(@"%@ invoke viewWillDisappear",self.ctrlName);
    [super viewWillDisappear:animated];
}

-(void) viewDidDisappear:(BOOL)animated
{
    NSLog(@"%@ invoke viewDidDisappear",self.ctrlName);
    [super viewDidDisappear:animated];
}

- (void)didReceiveMemoryWarning
{
    NSLog(@"%@ invoke didReceiveMemoryWarning",self.ctrlName);
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

-(void)dealloc
{
    NSLog(@"%@ .......dealloc.......",self.ctrlName);
}
3) 關(guān)鍵的遞歸函數(shù),核心是理解dismissViewControllerAnimated:completion函數(shù)中completion回調(diào)的時機點,這個是解題的鑰匙。
-(void)doDismiss
{
    NSLog(@"%@ dismiss begin",self.ctrlName);

    if([self.parentController isKindOfClass:[ViewController class]])
    {
        [self dismissViewControllerAnimated:YES completion: ^(void)
         {
             NSLog(@"%@ dismiss end",self.ctrlName);

             if(self.parentController)
             {
                 [self.parentController doDismiss];
             }
         }];
    }
    else
    {
        [self dismissViewControllerAnimated:NO completion: ^(void)
         {
             NSLog(@"%@ dismiss end",self.ctrlName);

             if(self.parentController)
             {
                 [self.parentController doDismiss];
             }
         }];

    }
}
4) Demo頁面結(jié)構(gòu)如下圖: MainViewController-->SecondViewController-->Child1ViewController,然后直接跳回到MainViewController.

5) 所有的ViewController都繼承自我們自定義的BaseViewController,具有關(guān)鍵的doDismiss遞歸方法!

IOS視圖控制器導(dǎo)航及生命周期研究Demo

6) 看一下從MainViewController-->SecondViewController-->Child1ViewController-->MainViewController生命周期的相關(guān)信息:

a、啟動程序,進入MainViewController:
2017-02-11 17:25:16.964 navTest[933:17086] mainViewCtrl invoke viewDidLoad
2017-02-11 17:25:16.966 navTest[933:17086] mainViewCtrl invoke viewWillAppear
2017-02-11 17:25:16.975 navTest[933:17086] mainViewCtrl invoke viewDidAppear

b、從MainViewController→SecondViewController:
2017-02-11 17:28:29.717 navTest[933:17086] SecondViewController invoke viewDidLoad [先newController調(diào)用viewDidLoad]
2017-02-11 17:28:29.721 navTest[933:17086] mainViewCtrl invoke viewWillDisappear [然后oldController調(diào)用viewWillDisappear]
2017-02-11 17:28:29.722 navTest[933:17086] SecondViewController invoke viewWillAppear [然后newController調(diào)用viewWillAppear]
2017-02-11 17:28:30.229 navTest[933:17086] SecondViewController invoke viewDidAppear [然后newController調(diào)用viewDidAppear ]
2017-02-11 17:28:30.229 navTest[933:17086] mainViewCtrl invoke viewDidDisappear [然后oldController調(diào)用viewDidDisappear ]
2017-02-11 17:28:30.230 navTest[933:17086] mainViewCtrl present end
[最后oldController調(diào)用presentViewController完成回調(diào)被調(diào)用]

下面是presentViewController完成回調(diào)信息的輸出代碼,用來了解completion是在哪個階段被調(diào)用的,很重要的信息哦?。。?/p>

- (IBAction)ClickToEnterSecondController:(id)sender {
    SecondViewController* ctrl = [self.storyboard instantiateViewControllerWithIdentifier:@"second"];
    ctrl.parentController = self;
    ctrl.ctrlName = @"SecondViewController";
    [self presentViewController:ctrl animated:YES completion:^(void)
     {
         NSLog(@"%@ present end",self.ctrlName);
     }];
}

c、從Child1ViewController直接返回到MainViewController的流程(跳過SecondViewController)

- (IBAction)returnMainViewController:(id)sender {
    NSLog(@"**********************doDismiss*********************");
    [self doDismiss];
}

d、2017-02-11 17:30:30.634 navTest[933:17086] **doDismiss* [要開始調(diào)用doDismiss函數(shù)了,表示點擊了返回按鈕]
2017-02-11 17:30:30.635 navTest[933:17086] Child1ViewController dismiss begin  [輸出dismiss begin,表示調(diào)用了Child1ViewController的doDismiss遞歸函數(shù)]
2017-02-11 17:30:30.637 navTest[933:17086] Child1ViewController invoke viewWillDisappear [oldController viewWillDisappear]
2017-02-11 17:30:30.638 navTest[933:17086] SecondViewController invoke viewWillAppear [newController viewWillAppear]
2017-02-11 17:30:30.641 navTest[933:17086] SecondViewController invoke viewDidAppear [newController viewDidAppear]
2017-02-11 17:30:30.641 navTest[933:17086] Child1ViewController invoke viewDidDisappear [oldController viewDidDisappear ]
2017-02-11 17:30:30.641 navTest[933:17086] Child1ViewController dismiss end [關(guān)鍵時刻哦,oldController self dismissViewControllerAnimated: completion: 中的completion 回調(diào)被觸發(fā)了,它是在 oldController viewDidDisappear后被觸發(fā)的哦]
2017-02-11 17:30:30.641 navTest[933:17086] SecondViewController dismiss begin [這時候,從ChildViewController回彈到SecondViewController的流程完成了,接下來遞歸調(diào)用,要完成從SecondViewController回彈到MainViewController的過程,重復(fù)上面的流程而已]
2017-02-11 17:30:30.642 navTest[933:17086] Child1ViewController …….dealloc……. [Child1ViewController已經(jīng)完全消失了,因此內(nèi)存被析構(gòu)了,這樣確保內(nèi)存不會泄露哦]

下面是遞歸部分,和上面流程一樣,只是從SecondViewController回跳到MainViewController

2017-02-11 17:30:30.643 navTest[933:17086] SecondViewController invoke viewWillDisappear
2017-02-11 17:30:30.644 navTest[933:17086] mainViewCtrl invoke viewWillAppear
2017-02-11 17:30:31.156 navTest[933:17086] mainViewCtrl invoke viewDidAppear
2017-02-11 17:30:31.156 navTest[933:17086] SecondViewController invoke viewDidDisappear
2017-02-11 17:30:31.156 navTest[933:17086] SecondViewController dismiss end
2017-02-11 17:30:31.157 navTest[933:17086] mainViewCtrl dismiss begin
2017-02-11 17:30:31.157 navTest[933:17086] SecondViewController …….dealloc…….  [SecondViewController 內(nèi)存也很完美的被析構(gòu)掉,目前僅剩下MainViewController還活著]

show一下某銀行APP以前模擬器中的效果截圖,IOS開發(fā)還是非常令人非常愉悅的感覺!

IOS視圖控制器導(dǎo)航及生命周期研究Demo


×××:

IOS UIViewController 導(dǎo)航及生命周期Demo

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI