iOS App 启动过程:main 及生命周期

iOS App 启动过程(三),本文介绍 main() 函数之后的过程以及 controllerview 的生命周期。

main函数后

进入 mian() 之后需要设置 AppDelegate 为应用代理,代理会在 App 启动之后调用:

1
2
[AppDelegate application:didFinishLaunchingWithOptions:] //程序完成加载
[AppDelegate applicationDidBecomeActive:] //程序被激活

点击Home键时

1
2
[AppDelegate applicationWillResignActive:] //程序取消激活状态
[AppDelegate applicationDidEnterBackground:] // 程序进入后台

点击APP时

1
2
[AppDelegate applicationWillEnterForeground:] // 程序进入前台
[AppDelegate applicationDidBecomeActive:] // 程序被激活

UIViewController 的生命周期

1
2
3
4
5
6
7
8
9
10
11
initWithCoder:
awakeFromNib
loadView
viewDidLoad
viewWillAppear:
viewWillLayoutSubviews
viewDidLayoutSubviews
viewDidAppear:
viewWillDisappear:
viewDidDisappear:
dealloc

initWithNibName:bundle:

StoryBoard 创建 UIViewController 会调用这个方法。不要在这里做 View 相关操作,ViewloadView 方法中才初始化。

initWithCoder:

使用 StoryBoard 进行视图管理,StoryBoard 会自动初始化 UIViewController,方法 initWithNibName:bundle 不会被调用,initWithCoder 会被调用。

loadView

loadView 方法在 UIViewController 对象的 view 被访问且为空的时候调用。这是它与 awakeFromNib 方法的一个区别。在重写 loadView 方法的时候,不要调用父类的方法。self.view 是在 loadView 方法中创建并建立联系的,不要调用 [super loadView],要将自定义的 view 赋值给 self.view。如果该控制器没有 xib 文件,重写了 loadView 但没有做任何事情(也就是 self.view为空),在 viewDidLoad 中还使用了 self.view(self.view 为空时会调用 loadView),这样会造成死循环。

指定构造函数

UIViewController 有两个 Designated Initializer

1
2
initWithNibName: bundle:
initWithCoder:

UIView 的生命周期

当创建 view 时

1
2
3
4
5
6
willMoveToSuperview:
didMoveToSuperview
willMoveToWindow:
didMoveToWindow
layoutSubviews
drawRect:

当view销毁时

1
2
3
4
5
6
willMoveToWindow:
didMoveToWindow
willMoveToSuperview:
didMoveToSuperview
removeFromSuperview
dealloc

注意:

只会执行一次的方法有 removeFromSuperviewdealloc 两个方法,可以在这两个方法中执行释放内存、移除观察者、定时器等。

willRemoveSubview 是在 dealloc 后面执行的。如果有多个子视图,willRemoveSubview 会循环执行,直到移除所有子视图。

1
2
- (void)willMoveToSuperview:(nullable UIView *)newSuperview;
- (void)willMoveToWindow:(nullable UIWindow *)newWindow;

这两个方法可以根据参数判断,nil 则为销毁,否则为创建;

1
2
- (void)didMoveToSuperview;
- (void)didMoveToWindow;

这两个方法可以根据 self.superview 判断,nil 则为销毁,否则为创建。

layoutSubviews 的触发条件

  1. init 初始化不会触发 layoutSubviewsinitWithFrame 初始化时,当 rect 的值不为 CGRectZero 时会触发。
  2. addSubview 会触发 layoutSubviews
  3. 设置 view 的 Frame 会触发 layoutSubviews
  4. 滚动一个 UIScrollView 会触发 layoutSubviews
  5. 旋转 Screen 会触发父 UIView 上的 layoutSubviews

setNeedsLayout,标记为需要重新布局,不立即刷新,在下一轮 runloop 结束前刷新,layoutSubviews 一定会被调用。
layoutIfNeeded,如果有需要刷新的标记,立即调用 layoutSubviews;如果没有标记,不会调用 layoutSubviews

指定构造函数

UIView 有两个 Designated Initializer

1
2
initWithFrame:
initWithCoder: