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;
- ...
各種方法的執(zhí)行問題
待續(xù)
控制器切換時的執(zhí)行順序
push
假設(shè)現(xiàn)在有一個 AViewController(簡稱 Avc) 和 BViewController (簡稱 Bvc)图张,通過 navigationController 的 push 實現(xiàn) Avc 到 Bvc 的跳轉(zhuǎn)褐健,下面是各個方法的執(zhí)行執(zhí)行順序:
1. A viewDidLoad A的view已經(jīng)加載
2. A viewWillAppear A將要顯示
3. A viewDidAppear A已經(jīng)顯示
4. B viewDidLoad B的view已經(jīng)加載
5. A viewWillDisappear A將要消失
6. B viewWillAppear B將要顯示
7. A viewDidDisappear A已經(jīng)消失
8. B viewDidAppear B已經(jīng)顯示
可能對1-4
的log
都比較好理解壕翩。對5-8
的執(zhí)行順序如果不真實測試就不清楚了棚品。測試后為如上的執(zhí)行順序催享,那么為什么是這樣的順序呢杭隙?為什么就不可以是
...
6. B viewWillAppear B將要顯示
5. A viewWillDisappear A將要消失
8. B viewDidAppear B已經(jīng)顯示
7. A viewDidDisappear A已經(jīng)消失
開始筆者也百思不得其解,然后去群里問了下各種大佬因妙。
-
測試了不知道了
痰憎。 - ...
具體是為什么呢?通過使用https://github.com/BigZaphod/Chameleon查看push
的具體源碼可知攀涵。
-
UINavigationController.m
中的push方法中調(diào)用了 [self _updateVisibleViewController:animated];
- 在
_updateVisibleViewController
的實現(xiàn)中可以看到
[oldVisibleViewController beginAppearanceTransition:NO animated:animated];
[newVisibleViewController beginAppearanceTransition:YES animated:animated];
-
beginAppearanceTransition
的實現(xiàn)如下:
- (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
還有如下的調(diào)用
[oldVisibleViewController endAppearanceTransition];
[newVisibleViewController endAppearanceTransition];
-
endAppearanceTransition
的實現(xiàn)如下:
- (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];
}
}
}
}
- 如果把上面的調(diào)用全部看完后相信你已經(jīng)知道為什么用先前的執(zhí)行順序了吧铣耘,其實就是 Apple的調(diào)用順序問題∫怨剩【當(dāng)然也有這樣做的原因】
presentViewController
上面看了 push 時的執(zhí)行順序蜗细,那么我們是否可以看看
presentViewController
的執(zhí)行順序呢?使用同樣的方法可以清楚的看到怒详。但是執(zhí)行順序和push不一致炉媒。
1. A viewDidLoad A的view已經(jīng)加載
2. A viewWillAppear A將要顯示
3. A viewDidAppear A已經(jīng)顯示
4. B viewDidLoad B的view已經(jīng)加載
5. A viewWillDisappear A將要消失
6. B viewWillAppear B將要顯示
7. B viewDidAppear B已經(jīng)顯示
8. A viewDidDisappear A已經(jīng)消失