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-4
的log
都比较好理解。对5-8
的执行顺序如果不真实测试就不清楚了。测试后为如上的执行顺序,那么为什么是这样的顺序呢?为什么就不可以是
...
6. B viewWillAppear B将要显示
5. A viewWillDisappear A将要消失
8. B viewDidAppear B已经显示
7. A viewDidDisappear A已经消失
开始笔者也百思不得其解,然后去群里问了下各种大佬。
-
测试了不知道了
。 -
你当前的不处理好,怎么能让你要push的vc做别的事
。 - ...
- 只能是呵呵了。
具体是为什么呢?通过使用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已经消失
网友评论