app 的生命周期
APP的5种状态
- Not running未运行:app没启动或被迫终止。
- Inactive未激活:当前应用正在前台运行,但是并不接收事件(当前或许正在执行其它代码)。一般每当应用要从一个状态切换到另一个不同的状态时,中途过渡会短暂停留在此状态。唯一在此状态停留时间比较长的情况是:当用户锁屏时,或者系统提示用户去响应某些(诸如电话来电、有未读短信等)事件的时候。
- Active激活:当前应用正在前台运行,并且接收事件。这是应用正在前台运行时所处的正常状态。
- Backgroud后台:程序在后台而且能执行代码,大多数程序进入这个状态后会在在这个状态上停留一会。时间到之后会进入挂起状态(Suspended)。经过特殊的请求后可以长期处于Backgroud状态。
- Suspended挂起:程序在后台不能执行代码。系统会自动把程序变成这个状态而且不会发出通知。当挂起时,程序还是停留在内存中的,当系统内存低时,系统就把挂起的程序清除掉,为前台程序提供更多的内存。
执行流程
application:didFinishLaunchingWithOptions: 这是程序启动时调用的函数。
applicationDidBecomeActive: 应用在准备进入前台运行时执行的函数。
applicationWillResignActive: 应用当前正要从前台运行状态离开时执行的函数。
applicationDidEnterBackground: 此时应用处在background状态,并且没有执行任何代码,未来将被挂起进入suspended状态。
applicationWillEnterForeground: 当前应用正从后台移入前台运行状态,但是当前还没有到Active状态时执行的函数。
applicationWillTerminate: 当前应用即将被终止,在终止前调用的函数。如果应用当前处在suspended,此方法不会被调用。
APP启动
application:didFinishLaunchingWithOptions:
applicationDidBecomeActive按home键
applicationWillResignActive
applicationDidEnterBackground再次回到前台
applicationWillEnterForeground
applicationDidBecomeActive当URL请求到达时,如果你的应用没在正在运行,则会被启动并且移到前台运行以打开URL。
application:didFinishLaunchingWithOptions:
application:openURL:sourceApplication:
applicationDidBecomeActive当URL请求到来时,如果你的应用正在background运行或被suspended,它将会被移到前台以打开URL。
从第三方分享回来:
applicationWillEnterForeground
application:openURL:sourceApplication:
applicationDidBecomeActive当一个基于警告的中断(诸如电话来电)发生时,应用会暂时从active状态切换到Inactive状态,以给系统提供机会提示用户,让用户决定如何处理。在用户决定如何处理此中断警告之前,应用将一直处于Inactive状态。 在用户做出选择后,当前应用或者回到active状态继续运行,或者直接切换到background状态以让位于其它的应用运行。
对于基于警告的中断将会导致用户暂时对应用失去控制。当前应用继续在前台foreground运行,但是不再接收任何触控事件。(事实上,应用只是不再接收触控类事件,其它类型的事件比如accelerometer事件,和通知Notification,应用仍然接收。)当系统内存不足时,系统会强行关闭那些尚在内存中但处于后台状态的 app,以腾出足够的内存供使用。但是那些被强行关闭的程序不会调用任何UIApplicationDelegate的委托方法,只会得到一个KILL 信号。当我们长按app icon,强行关闭app,也是同样的处理过程。
ViewController 的生命周期
1 | init |
- init
init里不要出现创建view的代码。良好的设计,在init里应该只有相关数据的初始化,而且这些数据都是比较关键的数据。init里不要掉self.view,否则会导致viewcontroller创建view。(因为view是lazyinit的)。 - loadView
loadView只初始化view,一般用于创建比较关键的view如tableViewController的tabView,UINavigationController的navgationBar,不可掉用view的getter(在掉super loadView前),最好也不要初始化一些非关键的view。如果你是从nib文件中创建的viewController在这里一定要首先调用super的loadView方法,但建议不要重载这个方法。 - didReceiveMemoryWarning
当app收到内存警告的时候会发消息给视图控制器。
app从来不会直接调用这个方法,而是当系统确定可用内存不足的时候采取调用。
如果你想覆写这个方法来释放一些控制器使用的额外内存,你应该在你的实现方法中调用父类的实现方法。 - viewWillUnload:(iOS6废除)
- viewDidUnload:(iOS6废除)
view的加载过程
1.View创建:loadView
1.从Storyboard/Xib加载视图时会调用的方法
1).initWithCoder
2).awakeFromNib: 此时frameh还没有完成。
2.手写代码:
1).initWithCoder
2).initWithFrame,创建时init会调用此方法。不过此时frame为0,除非显示调用此方法,frame才会有值。
view采用懒加载的方式,只有用到view时才会被创建,即才会被调用loadView->viewDidLoad这一系列函数,控制器的View是延迟加载的: 创建控制器并不一定会创建控制器的view,等用到时再加载。
layoutSubViews
- layoutSubViews方法由系统来调用,不能程序员来调用。
- 可以调用setNeedsLayout方法进行标记,以保证在UI下个刷屏系统中会调用layoutSubviews。
- 可以调用layoutIfNeeded直接请求系统调用layoutSubviews。
layoutSubViews的被调用时机:
1.addSubView会触发layoutSubviews,比如ivewA add ViewB,第一次添加A和B的layoutSubviews都会被调用,而第二次( viewA 已经有了viewB)只调用viewB的。
2.view的frame改变会触发layoutSubViews。
3.滚动一个UIScrollView会触发layoutSubviews。
4.旋转Screen会触发UIView的layoutSubviews。
5.改变transform属性时,当然frame也会变。
6.处于key window的UIView才会被调用( 程序同一时间只有一个window为keyWindow,可以简单理解为显示在最前面的window的keywindow)。
UIScrollView 的代理方法调用顺序
1 | /***手离开屏幕时没有移动的速度(Pan)***/ |
+initialize 与 +load
调用时机
- initialize 方法:这个方法会在
第一次初始化这个类之前
被调用,我们用它来初始化静态变量。
- initialize 方法:这个方法会在
- initialize 方法类似一个懒加载,如果没有使用这个类,那么系统默认不会去调用这个方法,且默认只加载一次;
- initialize 的调用发生在 +init 方法之前。
创建子类的时候,子类会去调用父类的 + initialize 方法。
- load 方法:会在
加载类的时候就被调用
,也就是 ios 应用启动的时候,就会加载所有的类,就会调用每个类的 + load 方法。
没有对类做任何操作的情况下,+load 方法会被默认执行,并且是在 main 函数之前执行的。