iOS App生命周期
无论是基于C还是基于Objective-C的程序,程序的入口都是main
函数。在iOS中已为你创建好main
函数,如下:
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
UIApplicationMain
UIApplicationMain(_:_:_:_:)
官网解释为:
Creates the application object and the application delegate and sets up the event cycle.
创建application对象,和application的代理,设置事件循环
该方法有4个参数,着重看后面2个:
principalClassName
-指定应用程序类名(app的象征),该类必须是UIApplication
(或子类)。如果为nil
,则用UIApplication
类作为默认值delegateClassName
-指定应用程序的代理类,该类必须遵守UIApplicationDelegate
协议
在Programming iOS 10 Dive Deep into Views View Controllers and Frameworks
书中有这样的介绍:
1.UIApplicationMain
实例化UIApplication
,并保留这个实例,作为一个共享的application实例,可通过UIApplication.shared
来获取到。然后实例化app的代理类。它保留app的代理类,并把它指定为application实例的代理
2.UIApplicationMain
检查app是否使用了main storyboard
(通过Info.plist
文件中的UIMainStoryboardFile
来确定)。
3.如果使用main storyboard
,UIApplicationMain
实例化UIWindow
,并把window实例指派给app代理的window
属性。
4.如果使用了main storyboard
,UIApplicationMain
将实例化storyboard的初始控制器。并把这个控制器实例指派给window
的rootViewController
属性。当控制器成为主window的rootViewController
后,它的view将会成为主window的唯一直接子view——主window的根view。 主window中的所有其他view都是根view的子view
5.UIApplicationMain
调用app代理的application(_:didFinishLaunching- WithOptions:)
方法
6.此时app的界面还不可见,直到window成为app的关键window。如果使用了storyboard,UIApplicationMain
将调用window实例的makeKeyAndVisible
方法
app运行起来后,可以有多种方式来引用window
- 如果
UIView
在界面中,其window
属性会自动的指向这个window
。可通过UIView
的window
属性来判断view是否被嵌入到了window
中,如果其window
值为nil
,则对用户来说则不可见 app代理的
window
属性也维持着对window的引用。可通过如下的方法引用windowlet w = UIApplication.shared.delegate!.window!! //或者 let w = (UIApplication.shared.delegate as! AppDelegate).window!
共享的application的
keyWindow
属性也有引用windowlet w = UIApplication.shared.keyWindow!
但是这个引用,却不是固定的,因为系统可以创建临时窗口并将它们作为应用程序的关键窗口
UIApplication
在App Programming Guide for iOS中,如下的图,iOS App中的关键对象:
UIApplication的核心作用是提供了 iOS 程序运行期间的控制和协作工作。
每一个程序在运行期必须有且仅有一个 UIApplication
(或则其子类)的一个实例。在程序开始运行的时候,UIApplicationMain
函数是程序进入点,这个函数做了很多工作,其中一个重要的工作就是创建一个 UIApplication
的单例实例。在你的代码中你,你可以通过调用 [UIApplication sharedApplication]
来得到这个单例实例的指针。
UIApplication
的一个主要工作是处理用户事件,它会起一个队列,把所有用户事件都放入队列,逐个处理,在处理的时候,它会发送当前事件 到一个合适的处理事件的目标控件。此外,UIApplication
实例还维护一个在本应用中打开的 window 列表(UIWindow
实例),这样它就 可以接触应用中的任何一个 UIView
对象。
UIApplication
实例会被赋予一个代理对象,该代理遵循UIApplicationDelegate
协议,以处理应用程序的生命周期事件(比如程序启动和关闭)、系统事件(比如来电、记事项警告)等等。
app可以通过openURL(_ :)
方法处理资源,如电子邮件或图像文件。 例如,使用电子邮件URL调用此方法的应用程序会导致邮件应用程序启动并显示消息。
UIApplication
对象可以执行如下的操作:
1.临时挂起传入的触摸事件(beginIgnoringInteractionEvents())
2.注册远程通知(registerForRemoteNotifications())
3.触发撤消重做UI(applicationSupportsShakeToEdit)
4.是否有已安装应用可以处理URL Scheme(canOpenURL(_:))
5.扩展应用程序的执行,以便它可以在后台完成一个任务(beginBackgroundTask(expirationHandler:),beginBackgroundTask(withName:expirationHandler:))
6.发送和取消本地通知(scheduleLocalNotification(:), cancelLocalNotification(:))
7.协调远程控制事件的接收(beginReceivingRemoteControlEvents(), endReceivingRemoteControlEvents())
8.执行应用程序级别的状态恢复任务
绝大数app并不需要继承UIApplication
,而是使用app的代理来管理系统和应用程序之间的交互
如果你的应用程序必须在系统执行之前处理传入事件(这是非常罕见的情况),则可以实施自定义事件或动作分派机制。为此,可以继承UIApplication
,并重写 sendEvent(_:)
方法,和/或者sendAction(_:to:from:for:)
方法, 对于你截取的每个事件,在处理事件后通过调用[super sendEvent:event]
将其分派回系统
主RunLoop
app的 main run loop处理所有用户相关的事件。UIApplication
对象在启动时设置main run loop
,并使用它来处理事件和处理view界面的更新。顾名思义,主运行循环是运行在主线程上的,这样可确保用户相关事件按接收顺序进行连续处理。
下图显示了主运行循环的体系结构以及用户事件是如何导致应用程序执行操作的。 当用户与设备交互时,与这些交互相关的事件由系统生成并通过由UIKit设置的特殊端口传递给应用。 事件在应用程序内部排队,并逐个派发到主运行循环中执行。 UIApplication
对象是接收事件的第一个对象,并决定需要做什么。 触摸事件通常分派给主窗口对象,然后将其分派到发生触摸的视图。
iOS应用可以传递不同类型的事件。一些是在主运行循环中传递,而有些却不是。一些事件被发送给代理对象或者你提供的block
某些事件(如触摸和远程控制事件)由应用程序的responder对象处理。 响应者对象在您的应用程序中无处不在。 (UIApplication
对象,视图对象和视图控制器对象都是响应者对象的示例。)
生命周期
可参考Managing Your App’s Life Cycle
app总在如下5种状态中的一种