UIApplicationMain函数
1. iOS程序的启动
在C语言中,程序是从main开始执行的, 在一个iOS应用中,也是从main 函数开始执行的.该main函数和C语言中的main函数没有什么不同.不同的是该函数的返回值虽然是int ,但是它从来不会返回.即便你按下home键. 其实按下home键,应用只是进入到另外一个状态, 同时在应用内会收到特定的通知且回调特定的"回调方法". 这里不做叙述了,这是iOS应用生命周期的事情.
iOS应用的程序入口---main函数
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
该函数只有一个return 语句,该语句返回一个UIApplicationMain函数.可以看到该函数有四个参数.
2. UIApplicationMain函数
int UIApplicationMain(int argc, char *argv[ ], NSString * __nullable principalClassName, NSString * __nullable delegateClassName);
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.
The name of the UIApplication class or subclass. If you specify nil, UIApplication is assumed.
2.1 该函数有四个参数,第1,2个和main的参数一样, 重要的是第三个,第四个参数.其类型为NSString,分别代表两个类名(ClassName),文档上对这四个参数的描述是:如果principalClassName参数为nil,那么就去应用的info.plist中查找NSPrincipalClass键所对应的值,在info.plist中如果再没有这个键值对,就使用 @"UIApplication". Xcode和网站上的文档不一致,不知为何.第四个参数delegateClassName 和第三个参数类似, 指定代理类的名字.
3. UIApplicationMain 函数做了哪些事情?
3.1 在上面说了UIApplicationMain的四个参数,既然是UIApplicationMain函数需要这传入这几个参数,那么它肯定是需要用这些参数做一些事情.首先UIApplication函数会根据传入的第三个参数principalClassName,创建一个UIApplication(或UIApplication子类)对象.
3.2 然后UIApplicationMain函数在根据第四个参数提供的代理类的类名:delegateClassName,创建一个代理对象,把该代理对象设为3.1 中创建的UIApplication或其子类对象的代理.我们可以在工程目录中看到这个代理类,默认是"AppDelegate.h"和"AppDelegate.m".就是该代理类的.
3.3 开启main run loop . 开始事件循环,响应事件.
3.4 根据info.plist文件中的设置,判断是否指定storyboard或nib文件,如果有就去加载并做相应的设置.
这里重申一下:UIApplicationMain函数做的事情是创建对象,而不是类,它还没那么智能到去自动合成一个符合具体需求的类,系统倒是能创建默认的类,那都是写死的. 这个函数所做的只是根据类名找到所属的类,去创建该类的实例. 一般情况下我们都是使用系统默认的application类.然后创建一个默认的代理对象.APPDelegate对象.如果你不指定,这个类的创建也是默认的.
UIApplication类
听名字就可以猜测到根据这个类创建的对象是应用级的,事实也是如此.它是一个iOS应用程序的象征,在一个应用中只能有一个这种对象.它是个单例对象,我们从上面的加载顺序中就知道,它是被UIApplicationMain函数创建,而且是在应用程序执行过程中创建的第一个对象,因为它是一个iOS应用的象征,一个iOS应用只能有一个这种对象. 一般我们很少直接对UIApplication对象做操作.
- 我们不应该通过alloc来获取该对象,会报错---只能有一个UIApplication对象, 我们应该通过该类提供的一个类方法sharedApplication 来获取该对象.该类有两个重要的属性:windows , keyWindow. 还有一个代理属性后面会说到.我们可以使用该类提供的方法和属性来进行一些应用级别的操作和设置. 如联网指示器的显示与否,统一设置应用的状态栏,IconBadgeNumber 等...
UIApplication* application = [[UIApplication alloc]init];
reason: 'There can only be one UIApplication instance.' 不该直接通过alloc的方式获取APP对象.应该使用系统提供的类方法.
下面简单介绍通过APP对象设置统一设置状态栏显示效果,其他APP对象的应用级的使用...改天再细说
//统一设置APP状态栏的显示效果
//通过sharedApplication获取该程序的UIApplication对象
UIApplication *app=[UIApplication sharedApplication];
//设置状态栏的样式
app.statusBarStyle=UIStatusBarStyleDefault;//默认黑色
//使用方法设置样式和动画
[app setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];
//设置状态栏是否隐藏
app.statusBarHidden=YES;
//设置是否隐藏和动画
[app setStatusBarHidden:YES withAnimation:UIStatusBarAnimationFade];
UIApplicationDelegate
该第四个参数了,不对!现在说的,它比第四个参数还重要. 从参数名中可以看出第四个参数是代理类的名字,既然是代理(delegate),那可定需遵循一定的协议,没错!这个协议就是UIApplicationDelegate
The UIApplicationDelegate protocol defines methods that are called by the singleton UIApplication object in response to important events in the lifetime of your app.
这个代理中的方法会在应用运行生命周期中的一些重大时刻被UIApplication对象(就是前面那个被applicationMain函数创建的对象)回调,这个不难理解,这个协议就是UIApplication对象所委托代理对象做的事情.
既然官方文档都说了,在应用程序生命周期中所发生的一些重大事件才会回调这些方法,方法有限,看看都是哪些重大事件:
//挑几个眼熟的贴上来
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//设置window
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [[ViewController alloc]init];
[self.window makeKeyAndVisible];
return YES;
}
- (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 invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
- (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.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
- (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.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
都是从iOS工程目录中appDelegate.m文件中Copy来的*这个文件是系统默认生成的UIApplication对象的代理类,所以已经把遵守的协议给你带上了,直接在里面填代码就OK了.不过苹果的这种做法的确是让我们写程序是少废了不少功夫,但是给初学者在刚学习的时候,造成很大迷惑.很难对整个iOS应用的运行概况有个清晰的认识.
不知不觉,十二点了.睡吧.下次接着写... 发现越写东西越多,还担心写错,尽力把自己知道的都说写出来就OK啦. Good night !