程序员

iOS应用程序启动原理

2017-12-06  本文已影响0人  JustEverOnce

利用Xcode新建一个iOS 应用程序,不做任何操作,运行该应用程序,没有任何问题,我们没有做任何的配置,怎么就会正常运行呢,或者说该应用程序内部是怎么实现的,今天简单来探讨一下
首先新建工程之后的目录结构如下:


D95CDC9E-79CF-4C4A-8D92-9BFDA7DFB92D.png

Appdelegate中有几个方法,具体什么时候实现这里简单说明下,有兴趣的同学可以更深入的研究
这里简单的提供一个打印方法名称的代码

NSLog(@"%s", __func__);

具体如下所示:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"%s", __func__);
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    
    NSLog(@"%s", __func__);
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    
    NSLog(@"%s", __func__);
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    
    NSLog(@"%s", __func__);
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    
    NSLog(@"%s", __func__);
}

启动应用程序之后,控制台打印如下:
2017-12-06 21:20:15.322628+0800 Test[3249:149859] -[AppDelegate application:didFinishLaunchingWithOptions:]
2017-12-06 21:20:15.334504+0800 Test[3249:149859] -[AppDelegate applicationDidBecomeActive:]

该应用程序推入后台之后控制台打印如下:
2017-12-06 21:21:21.568254+0800 Test[3249:149859] -[AppDelegate applicationWillResignActive:]
2017-12-06 21:21:22.382829+0800 Test[3249:149859] -[AppDelegate applicationDidEnterBackground:]

点击应用图标再次进入应用程序,控制台打印如下:
2017-12-06 21:22:30.266842+0800 Test[3249:149859] -[AppDelegate applicationWillEnterForeground:]
2017-12-06 21:22:30.557568+0800 Test[3249:149859] -[AppDelegate applicationDidBecomeActive:]

多说一点这几个方法大概什么意思:
-[AppDelegate application:didFinishLaunchingWithOptions:]
上述方法在应用程序启动之后就会调用,并且只会调用一次

-[AppDelegate applicationDidBecomeActive:]
上述方法在应用程序获取焦点之后调用,此后你就可以与该App进行交互,按钮的点击等等。。。

-[AppDelegate applicationWillResignActive:]
上述方法在失去焦点的时候调用

-[AppDelegate applicationDidEnterBackground:]
上述方法在程序进入后台的时候调用

-[AppDelegate applicationWillEnterForeground:]
上述方法在程序即将进入前台的时候调用

-[AppDelegate applicationDidBecomeActive:]
程序获取焦点的时候调用

上述的几个步骤:
1.应用程序加载完成
2.应用程序获得焦点
3.应用程序失去焦点
4.应用程序进入后台
5.应用程序进入前台
6.应用程序获得焦点

下面说收为什么应用程序启动之后是如何进入AppDelegate中的,也就是经常说的程序入口之处,查看目录结构,你会发现有一个main.m的文件,这里是咩有main.h文件的啊,进去看看哈 ,具体代码如下所示:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

大胆猜一下,这个会不会是入口,毕竟没有main.h文件啊,打印下该方法看看,如下所示:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        
        NSLog(@"%s", __func__);
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

大胆运行控制台打印如下:
2017-12-06 21:42:03.393055+0800 Test[4428:221614] main
2017-12-06 21:42:03.481585+0800 Test[4428:221614] -[AppDelegate application:didFinishLaunchingWithOptions:]
2017-12-06 21:42:03.496284+0800 Test[4428:221614] -[AppDelegate applicationDidBecomeActive:]

该方法在-[AppDelegate application:didFinishLaunchingWithOptions:]之前运行,那就说明程序的真实入口 其实是在main方法中,但是main与AppDelegate有什么关系呢?

关键性的一句:
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));

借助Help查看UIApplicationMain 如下所示(主要看几个参数):

Parameters
argc
The count of arguments in argv; this usually is the corresponding parameter to main.

argv
A variable list of arguments; this usually is the corresponding parameter to main.

principalClassName
The name of the UIApplication class or subclass. If you specify nil, UIApplication is assumed.

delegateClassName
The name of the class from which the application delegate is instantiated. If principalClassName designates a subclass of UIApplication, you may designate the subclass as the delegate; the subclass instance receives the application-delegate messages. Specify nil if you load the delegate object from your application’s main nib file.

UIApplicationMain前两个参数,不用管,因为是就是main中的参数,具体的干什么的,我也不知道

看看第三个参数:
principalClassName
The name of the UIApplication class or subclass. If you specify nil, UIApplication is assumed.
翻译之后意思大概就是说:UIApplication类或子类的名称。 如果指定nil,那就设定为UIApplication。
那么我们试着换一下,不用nil,使用UIApplication的名称(注意:这里是名称啊,字符串啊,为什么就是字符串呢,查看API:
UIKIT_EXTERN int UIApplicationMain(int argc, char * _Nonnull * _Null_unspecified argv, NSString * _Nullable principalClassName, NSString * _Nullable delegateClassName);

修改如下:
return UIApplicationMain(argc, argv, @"UIApplication", NSStringFromClass([AppDelegate class]));
运行正常

第四个参数:
delegateClassName
The name of the class from which the application delegate is instantiated. If principalClassName designates a subclass of UIApplication, you may designate the subclass as the delegate; the subclass instance receives the application-delegate messages. Specify nil if you load the delegate object from your application’s main nib file.

翻译之后意思大概就是说传一个application delegate,我们程序中的其实就是AppDelegate,其实也是一个字符串,那我们就可以考虑替换下,修改如下:
return UIApplicationMain(argc, argv, @"UIApplication", @"AppDelegate");
运行正常

内部到底如何实现,产看帮助文档中如下描述:

Discussion
This function instantiates the application object from the principal class and instantiates the delegate (if any) from the given class and sets the delegate for the application. It also sets up the main event loop, including the application’s run loop, and begins processing events. If the application’s Info.plist file specifies a main nib file to be loaded, by including the NSMainNibFile key and a valid nib file name for the value, this function loads that nib file.

翻译下:
该函数实例化来自主类的应用程序对象,并实例化来自给定类的委托(如果有)并设置应用程序的委托。 它还设置了主事件循环,包括应用程序的运行循环,并开始处理事件。 如果应用程序的Info.plist文件指定要加载的主要nib文件,则通过包含NSMainNibFile键和该值的有效nib文件名称,该函数将加载该nib文件。

总结下可以归结如下:
1.创建UIApplication对象
2.创建UIApplication代理对象,并给其设置代理(就是AppDelagate)
3.开启主运行时间循环(Runloop),处理事件,保证程序运行时可以接受并处理各种事件
4.加载info.plist文件,判断是否指定main,指定就会加载

补充:开发中不建议修改main方法中的东西,这里是为了更好的理解,才做的修改

为了更好理解,补充一张流程图


8ACA9F91-7111-4637-8551-49F2213450E5.png

简单的就说这么多,希望可以帮助小白更好的理解。。。

上一篇下一篇

猜你喜欢

热点阅读