编写程序,最终要的就是,要知道程序从何处开始,从何处结束,中间过程的状态转换又是如何进行的。只有知道这些,才能在出现问题时候立马能发现问题的根本,迅速找出问题所在。
iOS程序启动,和其他基于C的程序一样,都有一个main方法,现在我们就来看看。
App启动过程:
int main(int argc, char * argv[]) {
@autoreleasepool {
returnUIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegateclass]));
}
@autoreleasepool {
returnUIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegateclass]));
}
}
这个main方法中,首先启动了一个 autoreleasepool ,这个是在最顶部的自动释放池。
// If nil is specified for principalClassName, the value for NSPrincipalClass from the Info.plist is used. If there is no
// NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init.
// NSPrincipalClass key specified, the UIApplication class is used. The delegate class will be instantiated using init.
UIKIT_EXTERNintUIApplicationMain(intargc,char*argv[],NSString*__nullableprincipalClassName,NSString*__nullabledelegateClassName);
进入这个 UIApplicationMain 函数定义,可以看到由于我们在 NSPrincipalClass 这个函数传递了nil,于是 UIApplicationDelegate 才得以起作用。我们也可以在 NSPrincipalClass 参数位置传递自定义的 UIApplication。
这个 UIApplicationMain 函数内部实现了:
1、用 StoryBoard 载入用户界面。
2、调用传入的 UIApplicationDelegate 的钩子方法来做一些程序加载之前的初始化操作。
3、将我们的App加入到程序 Main Run Loop 中,来响应和处理用户交互信息。
在启动过程中,会涉及到如下一些重要的角色:
UIApplication:
用来处理用户与设备交互的事件,并将其转发给对应的target object来处理。是整个App的核心调度模块。
UIApplicationDelegate:
只用来处理一些与整个App(而不是单个View)有关的事件。比如程序的启动加载、远程消息推送、App切换、App切回、App内存不足等事件。
CALayer:
属于 Core Animation 框架中的一个类,所有的控件和自绘制图形都是基于此类。
UIView:
开发人员使用最多的一个类。一般是使用其子类,绘制各种各样的图形。其中包含一个layer属性,所有内容都要在这个layer上绘制。当你发现 UIKit 框架提供的基本控件不能满足你的要求时,可以采用在 drawRect 函数中绘制,或者直接在 layer 属性上进行绘制。
UIWindow
继承自UIView,属于程序的顶层UIView,是一个基本容器,不显示内容。
由于继承自UIResponder,所以能够响应用户事件。
UIViewControl:
控制UIView的显示过程,接收事件,例如内存警告等。其中包含一个主UIView,所有的内容都在这个view或者其subview上绘制。
在程序启动过程中,会首先拉起一个 Main run loop 。相当于是这个 App 进程内的一个 while 循环,一直在后台运行。当有事件发生时候,操作系统首先会将事件通过对应的端口,放置到事件队列当中。App 的 Main run loop 就会获取到这个事件,并将其发送给 UIApplication ,由它来确定将事件发送给哪个对象。可以查阅事件分发规则:https://developer.apple.com/library/ios/documentation/EventHandling/Conceptual/EventHandlingiPhoneOS/Introduction/Introduction.html
App状态切换:
Not Running
程序未运行状态,程序没有启动。
Inactive
程序启动了,但还不能接收各种消息事件。
Active
程序在前台正常运行。
Background
这个状态可以接受消息。程序被切换到后台,会停留在这个状态一段时间,时间到之后,会被切换到Suspended状态挂起。
Suspended
程序被挂起,不能接收消息。在iOS系统内存过低时候,会将该状态的程序清除掉。下次再打开就相当于重新开启的状态。
接下来看看 UIApplicationDelegate 中的几个函数所对应的状态:
程序完成加载,此时处于Inactive 的状态。即将由 Inactive 进入 Active 状态。
– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
returnYES;
// Override point for customization after application launch.
returnYES;
}
程序已经进入 Active 状态。
– (void)applicationDidBecomeActive:(UIApplication *)application {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
程序即将由 Active 进入 Inactive 状态。
– (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
}
程序切换到后台,进入 Background 状态。
如果你的程序有一些需要在后台继续执行的功能,就需要在这个函数中进行处理了。
– (void)applicationDidEnterBackground:(UIApplication *)application {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
程序即将从后台被唤醒,进入前台。即进入 Active 状态。
– (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
// Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
}
程序即将被关闭时候调用。
– (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
最后用几张图片来直观的解释各个状态之间的切换过程:
程序启动:
程序被人为中断:
程序切换走:
程序切换回来:
锁屏: