iOS应用的执行原理
本文转自:http://www.cnblogs.com/oc-bowen/p/6061261.html
http://www.cnblogs.com/oc-bowen/p/6061178.html
一. iOS中常见文件
(一). Xcode6之前
- 创建项目,默认可以看见一个存放框架的文件夹
 - info文件以工程文件名开头,如:第一个项目-Info.plist
 - 项目中默认有一个PCH文件
 
(二). Xcode6之后(包括Xcode6)
- 创建项目,没有框架文件夹,使用时系统才去加载
 - info文件不以工程文件名开头,如:Info.plist
 - 项目中没有PCH文件
 
(三). Info.plist文件(项目配置文件)
- 作用:保存应用的信息,软件名称、版本号等等,相当于身份证
 - Bundle name:程序名称,不能超过12个字节
 - Bundle versions string, short:APP版本号
 - Bundle identifier:APP项目唯一标识
 - Bundle version:内部开发人员使用的版本号
 - Main storyboard file base name:第一启动的storyboard文件
 - 注意:图形化的Info.plist文件上面的KEY不是真实的KEY,要想看真实的KEY得看Info.plist文件的源码 
操作:Info.plist(选中后右键单击) -> Open As -> Source Code - 代码查看版本号
 
  NSDictionary *dicInfo = [NSBundle mainBundle].infoDictionary;
  NSLog(@"%@",dicInfo[@"CFBundleShortVersionString"]);
(四). PCH文件
PCH文件是一个头文件,能被项目中的其他所有源文件共享和访问
1. PCH文件的需求
一个宏或头文件等,很多文件都需要用到,怎么解决,搞个公用的头文件,同时导入这个头文件
2. 作用
(1). 存放一些公用的宏 
(2). 存放一些公用头文件 
(3). 管理日志的输出,自定义Log
3. 为什么要管理日志输出
因为日志输出非常耗性能,一般发布的时候不需要日志输出,只有调试的时候才需要
/*
...表示能接收任何参数
__VA_ARGS__ 表示左边...的参数会替代到右边NSLog中
*/
#ifdef DEBUG // 调试阶段
#define HMLog(...)  NSLog(__VA_ARGS__)
#else // 发布阶段
#define HMLog(...)
#endif
5. 注意
在PCH中写有关OC的语法,最好放在 #ifdef __OBJC__ 中,Xcode在每个OC文件中都定义了这个宏,也就意味着只有OC中的文件才拥有这些宏,避免了项目中有C文件的时候报错。
二. 程序的启动原理
(一). 程序的启动过程
- 打开程序
 - 执行main函数
 - 结束程序
 
(二). 执行main函数
int main(int argc, char * argv[]) {
    @autoreleasepool {
           // 第三个参数为nil时,默认是UIApplication类名
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}
1. UIApplicationMain函数的原型
UIKIT_EXTERN int UIApplicationMain(int argc, char *argv[], NSString *principalClassName, NSString *delegateClassName);
2. UIApplicationMain的底层实现
(1). 根据principalClassName提供的类名,创建一个UIApplication对象
a. UIApplication代表一个应用程序
b. UIApplication一般用来做一些应用级别的操作(app的提醒框,联网状态,打电话,打开网页,控制状态栏)
(2). 根据delegateClassName提供的类名,创建一个UIApplication的代理对象
a. 程序加载完毕时调用:application:didFinishLaunchingWithOptions:
b. 程序获取焦点时调用:applicationDidBecomeActive:
c. 程序进入后台时调用:applicationDidEnterBackground:
d. 程序失去焦点时调用:applicationWillResignActive:
e. 程序从后台回到前台时调用:applicationWillEnterForeground:
f. 内存警告,可能要终止程序时调用:applicationDidReceiveMemoryWarning:
g. 程序即将退出时调用:applicationWillTerminate:
(3). 开启一个主运行循环,它是保持程序一直在运行,并处理事件
(4). 加载Info.plist和启动图片,并且判断Info.plis有没有指定Main.storyboard,如果指定,就去加载
3. application隐藏状态栏
a. 设置Info.plist文件:添加健View controller-based status bar appearance,设置值为NO
b. 创建application
c. 调用隐藏状态栏方法
4. 补充:反射机制
反射机制好处:如果类名用字符串表示,即使类名写错,编译器不报错;如果通过反射机制,类名写错,编译器报错
NSString *className =  NSStringFromClass([AppDelegate class]);
Class strClass = NSClassFromString(@"AppDelegate");
(三). 加载Main.storyboard
1. 加载Main.storyboard步骤
a. 创建窗口
b. 加载Main.storyboard,并且加载Main.storyboard指定的控制器
c. 把新的控制器作为窗口的根控制器,并让窗口显示出来
2. 窗口(UIWindow)
a. UIWindow是一个特殊的UIView,在一个APP中一般都会有一个UIWindows,但不仅只有一个,如:软键盘也是一个窗口
b. APP程序启动完毕后,创建的第一个视图控件是UIWindow,接着创建控制器的View,最后将控制器的view添加到UIWindow上,于是控制器的view就显示在屏幕上
c. 一个APP之所以能显示到屏幕上,完全是因为有UIWindow
d. UIScreen : 标识物理的屏幕,它连接着设备
e. UIWindow : 用于提供屏幕绘制支持的,提供了一些绘图的方法
f. UIView : 窗口上有很多View,是用于提供绘图操作的,把画好的View添加到窗口上,就可以显示;屏幕上的东西都是绘制上去的,刷新一遍相当于重新绘制一遍
g. 只有加载Main.storyboard的时候才创建窗口(这里说的加载是系统自动加载)
h. 如果是自己代码加载Main.storyboard,需要自己代码创建窗口
3. 补充
a. 如果把新创建的控制器的View用addSubview:方法直接添加到窗口上,不会有旋转功能
b.设置窗口的根控制器rootViewController,会自动把控制器的View添加到窗口
c. 查看主窗口:application.keyWindow
d. 显示窗口:self.window.hidden = NO;
e. 查看程序的所有窗口:application.Windows
4. addSubView和rootViewController的区别
a. 直接用addSubView,控制器会被释放,控制器就不能处理事件
b. 直接用addSubView,控制器的view不会自动旋转
c. 用rootViewController,控制器不会被释放,而且控制器的view会自动旋转
d. 旋转事件 -> UIApplication -> Window -> rootViewController ->旋转控制器的view
5. makeKeyAndVisible方法底层所做的事情
a. 把窗口设置成主窗口,如:application.keyWindow = self.window;
b. 显示窗口,如:self.window.hidden = NO;
c. 注意:虽然底层会做上面两步,但不一定是上面的代码
6. 窗口的层级
windowLevel: UIWindowLevelNormal < UIWindowLevelStatusBar < UIWindowLevelAlert
UIWindowLevelNormal : 默认窗口的层级
UIWindowLevelStatusBar : 状态栏、键盘
UIWindowLevelAlert :UIActionSheet,UIAlearView
把window的层级设置为UIWindowLevelAlert ,就会显示在最前面
相同层级的窗口,想让其中一个显示,可以用那个窗口的层级加上一个数
7. 代码模仿storyboard的加载
注:要习惯代码创建窗口和控制器,因为开发中很少用到storyboard直接开发,老项目中没有storyboard
  // 创建窗口
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  // 加载storyboard
  // Main.storyboard文件名不用写后缀
  // 当写nil时,系统默认[NSBundle mainBundle]
  UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
  //创建控制器
  //方式1:代码创建控制器
  //UIViewController *vc = [[UIViewController alloc] init];
  //vc.view.backgroundColor = [UIColor whiteColor];
  //方式2:加载storyboard里面有箭头的控制器
  //UIViewController *vc = [storyboard instantiateInitialViewController];
  // 当加载storyboard里面的控制器,控制器所属哪个类,就是创建哪个类
  //NSLog(@"%@",NSStringFromClass([vc class]));
  //方式3:storyboard里面有多个控制器,加载对应标识的控制器
  UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:@"B"];
  //创建窗口的根控制器
  self.window.rootViewController = vc;
  // 显示窗口
  [self.window makeKeyAndVisible];
(四). 通过XIB创建控制器的view
1. 步骤
a. 创建一个控制器的类
b. 创建一个xib,并指定xib所描述的控制器,一个xib只能用来描述一个控制器,如果没有指定,就不能拖线指定控制器的view
注意:xib里可以有多个UIView,不能固定死 
c. 拖线指定xib中哪个UIView是控制器的view
选中File`s Owner,右键单击后,在弹出的对话框上拖线 
d. 代码加载xib中描述控制器的view
  //创建窗口
  self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
  // 方式一:明确initWithNibName:方法的两个参数
  //UIViewController *vc = [[ViewController alloc] initWithNibName:@"View" bundle:[NSBundle mainBundle]];
  // 方式二:initWithNibName:方法的两个参数,只明确第一个参数,省略第二个参数
  // bundle写nil时,系统默认[NSBundle mainBundle]
  //UIViewController *vc = [[ViewController alloc] initWithNibName:@"View" bundle:nil];
  // 方式三:initWithNibName:方法的两个参数都省略
  //UIViewController *vc = [[ViewController alloc] initWithNibName:nil bundle:nil];
  // 方式四:调用init方法
  UIViewController *vc = [[ViewController alloc] init];
  // 设置窗口的根控制器
  self.window.rootViewController = vc;
  // 设置程序的主窗口并显示窗口
  [self.window makeKeyAndVisible];
2. 注意
只有控制器的init方法,底层才会调用initWithNibName:bundle:方法
3. view的创建
a. 如果重写loadView,就根据自定义的view创建view
b. 如果没有重写loadView,就去查看有没有storyboard,有storyboard,就根据storyboard里描述的view创建;
c. 如果没有storyboard,就去查看有没有指定的xib,有指定的xib,就根据xib里描述的view创建;
d. 如果没有指定的xib,即nibName为nil时,就查看有没有与xib的拥有者同名的xib,但优选查看没有Controller的xib,如果查不到,就查看有没有与xib的拥有者完全同名的xib,如:xib的拥有者是ViewController,xib的文件名是View,就优先查看View.xib,根据它描述的view创建;如果没有文件名为View的xib,就去查看有没有名字为ViewController的xib,如果有就根据xib里描述的view创建
e. 如果以上的情况都没有,就创建一个空的View
4. 控制器的loadView方法
A. loadView的作用:自定义控制器的view,只要重写了这个方法,说明要自己创建view,就不会自动创建view
B. loadView什么时候调用:第一次使用view的时候调用,调用这个方法创建控制器的view。
C. loadView默认做法:如果storyboard描述了控制器的view,就会去加载storyboard的view
D. 注意:
a. 只要重写loadView方法,没有调用系统默认的做法,即不写[super loadView],就不会去加载storyboard或者xib来描述控制器的view b. 如果重写loadView方法,并且指定了nibName,loadView默认的做法会去加载xib的view c. 只要重写loadView方法,没有指定nibName,就不会自动去加载和控制器同名的xib d. 在重写loadView时,没有给self.view创建view,就使用self.view,会造成死循环 e. 如果是根控制器的view,自定义view的时候可以不设置尺寸,系统会自动设置;不是跟控制器就不行;可以用CGRctZeco表示,如:self.view = [[UIView alloc] initWithFrame: CGRctZeco]; f. 重写loadView方法时,不要写[super loadView];,因为重写该方法的目的是自定义view,重写了还要去加载storyboard里的view,
等于多此一举
5. xib和storyboard的区别
storyboard已经指定了控制器的view,不需要我们管,xib需要我们手动管理
6. 如何快速生成一个xib描述控制器的view
- 定义新的控制器的时候,勾选xib,会自动搞一个xib描述控制器的view
 - 会自动生成一个和控制器同名的xib,并且里面设置好了
 
(五). 控制器的View
1. view的生命周期
只要是View开头的都是View的生命周期方法 
loadView:第一次使用view的时候调用
viewDidLoad:控制器的view加载完成的时候调用
viewWillAppear:控制器的view即将显示的时候调用
viewDidAppear:控制器的view完全显示的时候调用
viewWillDisappear:控制器的view即将消失的时候调用
viewDidDisappear:控制器的view完全消失的时候调用
viewWillLayoutSubviews:控制器的view即将布局的时候调用
viewDidLayoutSubviews:控制器的view完全布局的时候调用
viewWillUnload:控制器的view即将销毁
viewDidUnload:控制器的view完全销毁
2. 内存警告处理
a. 处理过程
有内存警告 -> 调用didReceiveMemoryWarning方法 -> 判断控制器的View存不存在 -> 存在就判断能不能被释放(判断是不是正在显示在界面上) -> 能释放就调用ViewWillUnload -> 完全释放后就调用ViewDidUnload
b. 注意
内存警告处理时,ViewWillUnload和ViewDidUnload不一定被调用,因为这是系统自动判断的
iOS应用的执行原理的更多相关文章
- iOS app 程序启动原理
		
iOS app 程序启动原理 Info.plist: 常见设置 建立一个工程后,会在Supporting files文件夹下看到一个"工程名-Info.plist"的文件, ...
 - iOS分类底层实现原理小记
		
摘要:iOS分类底层是怎么实现的?本文将分如下四个模块进行探究分类的结构体编译时的分类分类的加载总结本文使用的runtime源码版本是objc4-680文中类与分类代码如下//类@interfaceP ...
 - [iOS 开发] WebViewJavascriptBridge 从原理到实战 · Shannon's Blog
		
前言:iOS 开发中,h5 和原生实现通信有多种方式, JSBridge 就是最常用的一种,各 JSBridge 类库的实现原理大同小异,这篇文章主要是针对当前使用最为广泛的 WebViewJavas ...
 - 【如何快速的开发一个完整的iOS直播app】(原理篇)
		
原文转自:袁峥Seemygo 感谢分享.自我学习 目录 [如何快速的开发一个完整的iOS直播app](原理篇) [如何快速的开发一个完整的iOS直播app](播放篇) [如何快速的开发一个完整的 ...
 - iOS:app直播---原理篇
		
[如何快速的开发一个完整的iOS直播app](原理篇) 转载自简书@袁峥Seemygo:http://www.jianshu.com/p/7b2f1df74420 一.个人见解(直播难与易) 直播 ...
 - Javascript之数据执行原理探究
		
Javascript在Web服务器端执行原理: 1.客户端请求数据,即我们在上网时在地址栏中输入某个网址,浏览器接收到数据之后,向远程web服务器发送请求报文. 2.web服务器响应请求,web服务器 ...
 - Python程序的执行原理(转载)
		
Python程序的执行原理 2013-09-17 10:35 佚名 tech.uc 1. 过程概述 Python先把代码(.py文件)编译成字节码,交给字节码虚拟机,然后虚拟机一条一条执行字节码指令 ...
 - smarty模板执行原理
		
为了实现程序的业务逻辑和内容表现页面的分离从而提高开发速度,php 引入了模板引擎的概念,php 模板引擎里面最流行的可以说是smarty了,smarty因其功能强大而且速度快而被广大php web开 ...
 - MapReduce调度与执行原理之任务调度
		
前言 :本文旨在理清在Hadoop中一个MapReduce作业(Job)在提交到框架后的整个生命周期过程,权作总结和日后参考,如有问题,请不吝赐教.本文不涉及Hadoop的架构设计,如有兴趣请参考相关 ...
 
随机推荐
- 一分钟sed入门
			
[转载于58同城沈剑] 1.简介 sed是一种行编辑器,它一次处理一行内容. 2.sed调用方式 sed [options] 'command' file(s) sed [options] -f sc ...
 - 转: WebView载入一个网页 但是退出对应的activity时, 声音、视频无法停止播放 解决方案(未验证)
			
1. webview.onPause 2. webview独立进程,杀进程3.小场景可以不用这么复杂有个技巧就是在activity退出的时候加载一个空白页面,就能解决
 - 倍福TwinCAT(贝福Beckhoff)基础教程3.1 TwinCAT如何编写简单的计算器
			
把编写简单计算器作为入门的第一个范例程序,主要是因为比较简单,而且综合了HMI,数据类型,数据转换,PRG和FBD等功能块的混合等知识,个人认为还是比较适合用来快速上手的.由于是第一个范例,所以视频教 ...
 - 系统重装 VISTA下如何删除EISA分区
			
现在的品牌电脑大部分都有一键还原,把还原内容存储在EISA配置的隐藏分区里面,一般的软件都无法对其进行操作,保证分区及系统还原的安全性.这样的功能对于一些人不使用一键还原(笔者即是)来说实属鸡肋功 ...
 - 【VBA】复制单元格数据有效性
			
单元格内设置了有效性,通过VBA怎么去复制呢?代码如下: Public Sub 复制单元格批注() Dim range1 As range Dim range2 As range '清除G列 Colu ...
 - 我是怎样理解web页面的
			
事实上web页面包括三部分东东 1.页面展示的元素(HTML) 2.页面元素展示的样式(CSS) 3.控制页面元素的交互(JavaScript) 不管页面多么复杂,从这三方面去看,都会得到清晰的认识的 ...
 - C#写csv文件
			
1.在项目中经常需要把报表下载为csv格式的文件,如何在C#中写csv文件,以下为一个简化的例子,不使用任何控件,旨在说明用法. 前端view 下载结果 2.创建一个MVC项目(Intranet Ap ...
 - ios 抓包工具 ios青花瓷charles
			
iOS_青花瓷Charles抓包,ios青花瓷charles 使用青花瓷Charles抓取手机端的网络请求: 第一步,下载安装并打开Charles 第二步,去掉菜单[Proxy]以下的[Mac OSX ...
 - mysql innodb_data_file_path配置增加
			
在配置innodb_data_file_path=ibdata1:200M:autoextend时,想增加空间,默认文件不断增加直到200M,如果要增加大小,直接修改参数增加大小会报错: auto-e ...
 - mysql的UNIX_TIMESTAMP用法
			
UNIX_TIMESTAMP 一般是用于unix的时间戳. 例子: SELECT UNIX_TIMESTAMP("2016-07-11")-- 1468166400SELECT U ...