iOS 中 UIKit 一些 Api 的调用时机

2017/12/13 iOS 共 2211 字,约 7 分钟

UIKit 是 iOS 开发用来创建 UI 的框架,但它的 Api 定义并非清晰易懂,仅仅依靠文档有时并不能正确的使用。在不合理的时机调用会带来难以预料的UI异常,并且这些异常都难以调试,这里通过一些测试后,总结一下这些容易让人迷惑的 Api,避免在错误的时机调用他们。

UIViewController 的生命周期函数

loadView

  • 加载控制器管理的 view。
  • 每次访问 UIViewController 的 view 时候并且 view == nil 时候调用。
  • 调用此方法时若控制器有关联的 Nib 文件,该方法会从 Nib 文件中加载 view;如果没有,则创- 建空白 UIView 对象。
  • 如果使用 Interface Builder 创建 view,则务必不要重写该方法。
  • 如果你覆盖了loadView方法,则必须创建 view 给 UIVIewController 的 view 属性,如果你没有覆盖方法,UIViewController 会默认调用父类的方法加载初始化 view

viewDidLoad

  • view 被加载到内存后调用
  • 该方法中可以额外初始化控件,例如添加子控件,添加约束。

viewWillAppear

  • 该方法在控制器 view 即将添加到视图层次时以及展示 view 时所有动画配置前被调用
  • 该方法中可以进行操作即将显示的 view,例如改变状态栏的取向,类型。
  • 该方法被调用意味着控制器将一定会显示。

viewWillLayoutSubviews

  • 该方法在通知控制器将要布局 view 的子控件时调用。
  • 该方法调用时,AutoLayout 未起作用。
  • 在控制器生命周期中,该方法可能会被多次调用。

viewDidLayoutSubviews

  • 该方法在通知控制器已经布局 view 的子控件时调用。
  • 该方法可重写以在 view 布局子控件后做出改变。
  • 该方法调用时,AutoLayout 已经完成。
  • 在控制器生命周期中,该方法可能会被多次调用。

viewDidAppear

  • 该方法在控制器 view 已经添加到视图层次时被调用。
  • 该方法可重写以进行有关正在展示的视图操作。
  • 在控制器生命周期中,该方法可能会被多次调用。

viewWillDisappear

  • 该方法在控制器 view 将要从视图层次移除时被调用。
  • 该方法可重写以提交变更,取消视图第一响应者状态。

viewDidDisappear

  • 该方法在控制器 view 已经从视图层次移除时被调用。
  • 该方法可重写以清除或隐藏控件。

didReceiveMemoryWarning

  • 当内存预警时,该方法被调用
  • 该方法可重写以释放资源、内存。

dealloc

  • 控制器销毁时(离开堆),调用该方法。

initWithCoder

当控件是从 xib、storyboard 中创建时调用。

intWithFrame

当控件不是从 xib、storyboard 中创建时调用。

awakeFromNib

当控件是从 xib、storyboard 中创建时,在 initWithCoder 方法后调用,此时约束尚未生效,不要在这里修改控件的 frame。

drawRect

iOS 的绘图操作是在 UIView 类的 drawRect 方法中完成的,如果我们要想在一个 UIView 中绘图,需要重写一个 UIView 的 drawRect 方法,在这里进行绘图操作,程序会自动调用此方法进行绘图。

drawRect是在 Controller的viewWillAppear 之后调用的。可以在控制器中设置一些值给 View,如果这些 View draw 的时候需要用到某些变量值。

setNeedsDisplay

在 UIView 中,重写 drawRect 方法,可以自己定义想要画的图案,且此方法一般情况下只会画一次。也就是说这个 drawRect 方法一般情况下只会被掉用一次。 当某些情况下想要手动重画这个 View,只需要调用 setNeedsDisplay 方法即可。

layoutSubviews

这个方法用来更新布局,默认没有做任何事情,需要子类进行重写。系统在很多时候会去调用这个方法:

  1. init 初始化不会触发 layoutSubviews,但是是用 initWithFrame 进行初始化时,当 rect 的值不为 CGRectZero 时,也会触发
  2. addSubview 会触发 layoutSubviews
  3. 设置 view 的 Frame 会触发 layoutSubviews,当然前提是 frame 的值设置前后发生了变化
  4. 滚动一个 UIScrollView 会触发 layoutSubviews
  5. 旋转 Screen 会触发父 UIView 上的 layoutSubviews 事件
  6. 改变一个 UIView 大小的时候也会触发父 UIView 上的 layoutSubviews 事件

layoutIfNeeded

常用于代码中让 View 约束立即生效来执行动画,建议对修改 View 的父 View 执行。

setNeedsLayout

标记为需要重新布局,不立即刷新,在下一轮 runloop 结束前 layoutSubviews 一定会被调用

viewDidLoad 中设置 ib frame 无效的问题

加载 ib 文件约束是在 viewWillLayoutSubviews 开始的,查看生命周期发现,viewDidLoad 会在 viewWillLayoutSubviews 前执行,所以 viewDidLoad 中设置的 frame 又被改成了 ib 中的样子。解决办法有下面两种。

  1. 在 viewDidLayoutSubviews 中修改 frame。
  2. 将 xib 中的约束拖到 Controller 中成为 IBOutlet 的属性,然后修改该属性。

文档信息

Search

    Table of Contents