您好,登錄后才能下訂單哦!
2014年4月份第一次接觸IOS端開發(fā),為某銀行開發(fā)一款金融app。
在開發(fā)的最后階段,加入了需要從任意一個頁面直接返回主頁的功能。
悲催的是,當時沒有使用UINavigationController進行導(dǎo)航管理,而是使用了IOS中的模態(tài)跳轉(zhuǎn)方式(presentViewController/dismissViewControllerAnimated).
因此需要找的一種方法進行,實現(xiàn)如下方式的導(dǎo)航跳轉(zhuǎn):
面對上面的需求,最簡單的方式是將所有控制器都改成UINavigationController,并且利用pushViewController / popToViewController/ popToRootViewControllerAnimated 等方法進行完美解題。但是當時項目的頁面將近100個,分成三大模塊,需要大規(guī)模修改設(shè)計頁面以及調(diào)整大量代碼,這并不是一個現(xiàn)實的解決方案,不到萬不得已,不能采取如此低劣手段!
我們需要一個滿足如下條件的解決方案:
1) 對于已經(jīng)在InterfaceBuilder中完成的頁面,不做任何修改 2) 盡量少的修改代碼,因為很多代碼已經(jīng)經(jīng)過測試中心測試過,如果修改,需要全部重新測試,時間來不及。
當時通過兩天的研究,深入的了解了IOS中的跳轉(zhuǎn)流程和生命周期后,找到了一個相對完美的解決方案,能夠滿足上面提到的要求。通過一個Demo,來和大家一起分享。
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遞歸方法!
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)存不會泄露哦]
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 UIViewController 導(dǎo)航及生命周期Demo
免責聲明:本站發(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)容。