UIViewController 生命周期的一點思考和實踐

UIViewController 生命周期的一點思考和實踐

說到UIViewController的生命周期,可能第一時間會想到下面的各種方法

- (instancetype)init;
- (instancetype)initWithCoder:(NSCoder *)aDecoder;
- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;

- (void)loadView;
- (void)viewDidLoad; // Called after the view has been loaded. For view controllers created in code, this is after -loadView. For view controllers unarchived from a nib, this is after the view is set.
- (void)viewWillAppear:(BOOL)animated;    // Called when the view is about to made visible. Default does nothing
- (void)viewDidAppear:(BOOL)animated;     // Called when the view has been fully transitioned onto the screen. Default does nothing
- (void)viewWillDisappear:(BOOL)animated; // Called when the view is dismissed, covered or otherwise hidden. Default does nothing
- (void)viewDidDisappear:(BOOL)animated;  // Called after the view was dismissed, covered or otherwise hidden. Default does nothing
- (void)viewWillLayoutSubviews;
- (void)viewDidLayoutSubviews;
- ...

各種方法的執行問題

待續

控制器切換時的執行順序

push

假設現在有一個 AViewController(簡稱 Avc) 和 BViewController (簡稱 Bvc),通過 navigationController 的 push 實現 Avc 到 Bvc 的跳轉,下面是各個方法的執行執行順序:

1. A viewDidLoad        A的view已經加載
2. A viewWillAppear     A將要顯示
3. A viewDidAppear      A已經顯示
4. B viewDidLoad        B的view已經加載
5. A viewWillDisappear  A將要消失
6. B viewWillAppear     B將要顯示
7. A viewDidDisappear   A已經消失
8. B viewDidAppear      B已經顯示

可能對1-4log都比較好理解。對5-8的執行順序如果不真實測試就不清楚了。測試后為如上的執行順序,那么為什么是這樣的順序呢?為什么就不可以是

...
6. B viewWillAppear     B將要顯示
5. A viewWillDisappear  A將要消失
8. B viewDidAppear      B已經顯示
7. A viewDidDisappear   A已經消失

開始筆者也百思不得其解,然后去群里問了下各種大佬。

  • 測試了不知道了
  • ...

具體是為什么呢?通過使用https://github.com/BigZaphod/Chameleon查看push的具體源碼可知。

  • UINavigationController.m中的push方法中調用了
  • [self _updateVisibleViewController:animated];
  • _updateVisibleViewController的實現中可以看到
    [oldVisibleViewController beginAppearanceTransition:NO animated:animated];
    [newVisibleViewController beginAppearanceTransition:YES animated:animated];
  • beginAppearanceTransition的實現如下:
- (void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated
{
    if (_appearanceTransitionStack == 0 || (_appearanceTransitionStack > 0 && _viewIsAppearing != isAppearing)) {
        _appearanceTransitionStack = 1;
        _appearanceTransitionIsAnimated = animated;
        _viewIsAppearing = isAppearing;
        
        if ([self shouldAutomaticallyForwardAppearanceMethods]) {
            for (UIViewController *child in self.childViewControllers) {
                if ([child isViewLoaded] && [child.view isDescendantOfView:self.view]) {
                    [child beginAppearanceTransition:isAppearing animated:animated];
                }
            }
        }

        if (_viewIsAppearing) {
            [self view];    // ensures the view is loaded before viewWillAppear: happens
            [self viewWillAppear:_appearanceTransitionIsAnimated];
        } else {
            [self viewWillDisappear:_appearanceTransitionIsAnimated];
        }
    } else {
        _appearanceTransitionStack++;
    }
}
  • _updateVisibleViewController還有如下的調用
[oldVisibleViewController endAppearanceTransition];
[newVisibleViewController endAppearanceTransition];
  • endAppearanceTransition的實現如下:
- (void)endAppearanceTransition
{
    if (_appearanceTransitionStack > 0) {
        _appearanceTransitionStack--;
        
        if (_appearanceTransitionStack == 0) {
            if ([self shouldAutomaticallyForwardAppearanceMethods]) {
                for (UIViewController *child in self.childViewControllers) {
                    [child endAppearanceTransition];
                }
            }

            if (_viewIsAppearing) {
                [self viewDidAppear:_appearanceTransitionIsAnimated];
            } else {
                [self viewDidDisappear:_appearanceTransitionIsAnimated];
            }
        }
    }
}
  • 如果把上面的調用全部看完后相信你已經知道為什么用先前的執行順序了吧,其實就是 Apple的調用順序問題。【當然也有這樣做的原因】

presentViewController

上面看了 push 時的執行順序,那么我們是否可以看看presentViewController的執行順序呢?使用同樣的方法可以清楚的看到。但是執行順序和push不一致。

1. A viewDidLoad        A的view已經加載
2. A viewWillAppear     A將要顯示
3. A viewDidAppear      A已經顯示
4. B viewDidLoad        B的view已經加載
5. A viewWillDisappear  A將要消失
6. B viewWillAppear     B將要顯示
7. B viewDidAppear      B已經顯示
8. A viewDidDisappear   A已經消失
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容