一步一步分析新建App启动过程

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一步一步分析新建App启动过程相关的知识,希望对你有一定的参考价值。

ios温故而知新(一)  一步一步分析新建App启动过程   

 
 
 
笔者接触IOS大概半年的时间,可以说能够开发App,但是又有很多不足的地方,因此打算写一些技术文章,能够达到温故而知新的效果,难免会有错误或者遗漏,也希望各位看官不吝指教。另外宣传一下刚建立的群“IOS菜鸟到高手之路”,312747764,欢迎希望交流分享的人加入。

1、IOS系统的简单说明
IOS与Mac OS X以及安卓一样都属于类UINX系统,然而熟悉类UNIX系统的人可能会失望的是,个人开发的App会进入类似chroot的状态,被操作系统隔离开来,这就是所谓的沙盒,无法知晓其他应用程序,也无法访问文件系统,无法直接使用硬件——可以通过IOS提供的框架进行申请访问,mmap也在底层被修改以防止直接写内存页面的操作。如果要在IOS下进行开发,还是老老实实的使用IOS提供的框架吧。


2、建立一个新的App
环境:Xcode6
使用Xcode建立一个新的工程New Project,选择默认的Single View Application,然后命名,一个新的App就诞生了,可以直接运行在模拟器,如果有开发者账号,也可以配置后直接连接机器,新机器的通用签名,点击Fix Issue即可,Xcode会搞定剩余的事情,这里就不细说了。


3、App的开始
尽管已经建立了一个App,对于它的执行过程我们还是一无所知,让我们首先找到它的入口,Support Files/main.m
1
        return UIApplicationMain(argc, argv, nilNSStringFromClass([AppDelegate class]))

众所周知,main函数是C语言程序的入口,同样的它也是Objective C的入口
从直观的角度猜测,UIApplicationMain如果返回,则程序会结束,所以它会在结束时返回或者永远不会返回,而传入的可控参数则是最后一个参数,是一个类的名字。
实际上,UIApplicationMain函数永远不会返回,它负责对于建立程序执行所需要的类,进行初始化,并使程序进入事件等待的循环中,而最后一个参数则指明了程序执行所需的代理类。


4、AppDelegate 
让我们首先找到文件AppDelegate.m
除了修改代理协议的类,main.m几乎没有什么可以改动的地方,AppDelegate才是开发者大展拳脚的地方,几乎一切对于程序的控制都始于这里,程序的初始化,状态的改变都需要在这里得到响应。
可能新建程序的你要迷茫了,尽管可以看到(void)applicationWillResignActive这种有关状态切换的函数,明明什么代码都没有,界面又是如何显示的?


5、UIWindow
为了搞清界面显示的问题,首先要知道IOS进行显示,需要一个UIWindow类,来管理和定位各种视图(Views)。
为了测试,我们加入如下代码
1
2
3
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(“window is %@”, self.window)
}

执行后,显示
window is <UIWindow: 0x7f9a29532380; frame = (0 0; 375 667); hidden = YES; gestureRecognizers = <NSArray: 0x7f9a2952dab0>; layer = <UIWindowLayer: 0x7f9a2952f490>>
已经有值,可以推断,UIWindow在UIApplicationMain里面已经建立,那么问题来了,它是如何建立的?


6、Storyboard
在已经存在的文件中,最大的嫌疑就是它了,Main.storyboard,点击它我们可以很直观的发现,就是它在控制显示。Storyboard是IOS5以后推出的画板功能,可以比较方便的实现场景的转换和界面的布局,是一个便利的功能,相对的,有点不利于对于程序本身的理解。
然而到这里我们并没有搞清楚,UIApplicationMain是如何加载Storyboard的。


7、Info.plist
锁定最后的嫌疑人,就是它了。Info.plist可以看做是一个配置文件,它属于IOS bundle概念里必备的文件,可以通过man plist来查看格式,在IOS App中,可以直接将它看做一个字典。
在Info.plist中,可以找到:
“Main storyboard file base name”  String “Main”
在这里我们把“Main”改成”xx”, 试试看。
程序执行崩溃,不过不要慌张,看看结果
1
2
    3   UIKit                               0x0000000101170059 -[UIApplication _loadMainStoryboardFileNamed:bundle:] + 40
    4   UIKit                               0x000000010116f0cb -[UIApplication _runWithMainScene:transitionContext:completion:] + 1074

证明了正是UIApplication在之前加载了storyboard
删掉这个条目, 再启动,屏幕变成了黑屏
日志显示 window is (null)


8、手动添加window
1
2
3
4
5
6
7
8
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; //全屏window
    self.window.backgroundColor = [UIColor whiteColor]; //白色背景
    [self.window makeKeyAndVisible]; //
  
    return YES;
}

启动,白屏幕,成功


9、总结
虽然废了一番功夫,不过弄清以后就比较简单了,App通过UIApplicationMain进入,根据Info.plist里的信息执行初始化(如果有Storyboard则加载),随后执行(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions中的内容 ,执行完毕后,进行界面绘制,最后启动完毕,进入事件等待循环。

以上是关于一步一步分析新建App启动过程的主要内容,如果未能解决你的问题,请参考以下文章

一步一步实现字母索引导航栏

一步一步,一步 从代码到,打包成为手机App,上传至nginx服务器 (Vue项目)

一步一步学毕业设计:简单的MVC登录

swift——启动页国际化:一步一步动态加载启动页图片,启动的时候加载文字

一步一步带你分析 requirejs

Spring启动过程源码分析基本概念