iOS深入学习:构建阶段、编译器错误和连接器错误
iOS深入学习:构建阶段、编译器错误和连接器错误
召唤攻城狮 发表于4年前
iOS深入学习:构建阶段、编译器错误和连接器错误
  • 发表于 4年前
  • 阅读 788
  • 收藏 4
  • 点赞 2
  • 评论 0

新睿云服务器60天免费使用,快来体验!>>>   

摘要: Xcode应用程序运行的过程,我们真的懂了吗?

我建了一个iOS开发QQ交流群:188647173,大家可以一起来相互学习。

还有一个群里面大神的个人站点www.mylonly.com,大家有不会的可以向他请教。


Xcode会分步骤构建应用,这些步骤成为构建阶段,各个阶段所做的事情如下,

(1)编译源代码(Compile Sources):该阶段包含构建响应目标时需要编译的源代码。凡是加入项目中的源代码,默认都会加入该构建阶段。

(2)连接二进制文件和库(Link Binary with Libraries):完成代码的编译后,Xcode会将其和框架(库)连接,使代码能够使用相应框架中的类。

(3)拷贝程序包资源(Copy Bundle Resources):完成代码的编译和连接后,Xcode会生成一个可执行文件,并将其放入应用程序包(程序包其实是一个目录)。接着,Xcode会将拷贝程序包资源阶段中的文件加入程序包。这些资源是运行应用时需要使用的数据文件,例如ViewController.xib、图片和声音文件。这些都是应用程序的组成部分。凡是加入项目的非源代码文件,默认都会加入该构建阶段。

通常会在编译源代码的时候发现错误,连接二进制文件和库的阶段有时也会出错,如果了解各个阶段的作用,就可以更快地诊断和修正各个阶段产生的错误。

其实上述所说的三个过程,在Xcode中有所展示,可能我们都不知道罢了,项目配置文件->Build Phrases,如下图,

PS:“0依赖关系”这涉及到包依赖关系,我leader跟我说他最自豪的就是对于“包依赖关系”的掌控,这方面我还不是特别了解,还要多多学习。


下面主要说下编译阶段和连接阶段,

编译阶段--------预处理编译

编译源代码分为两个步骤:预处理和编译。

预处理:预处理的作用是为每个实现文件(.m)创建一个中间文件(intermediate file)。中间文件和实现文件一样,都是Objective-C代码,但是中间文件的体积可能会很大。

预处理器(preprocessor)处理完实现文件中的全部预处理指令后,会生成一个中间文件。与处理指令四大有哎#的语句,例如#import、#define。。。,预处理器在处理#import语句时,会将该语句天换成导入文件的内容。例如ViewController.m文件中包含ViewController.h文件,ViewController.m生成的中间文件会包含ViewController.h和ViewController.m的全部代码。不仅如此,ViewController.h文件中还可能包含UIKit.h和CoreLocation.h,这两个文件会导入更多的文件,导入的文件再导入其他文件,以此类推,ViewController.m的中间文件是这些文件的代码的集合

可能有的童鞋没有明白为什么预处理是在编译代码之前,我通过代码来说明一下吧,我们通过#define定义一个常量Debug,然后在#if~#elif~#endif中使用Debug常量,当然这里的#if~#elif~#endif要在大括号{}中使用,例如将#if~#elif~#endif写在-(viod)viewDidLoad{...}中,

#define Debug 0

#if Debug

    NSLog(@"Debug is 0");

#elif

    NSLog(@"Debug is not 0");

#endif

我们在Xcode中看这段代码的效果,如下图,

大家看出上面图片中NSLog颜色的不同吗?此时Debug为0,所以#if Debug后面的代码不会在编译的时候被编译,#else后面的代码会在编译的时候被编译,上面的代码也说明在预处理阶段,就确定了哪些代码会被编译。所以说预编译阶段就是在编译之前。

编译:预处理完成后,Xcode会编译之前生成的中间文件。Objective-C代码会被转换成机器码,保存在目标文件中(object file)。一个目标文件对应一个中间文件。在应用开发阶段,大部分错误会发生在这个将代码转换成机器码的编译阶段,编译器“看不懂”代码时会报错,这些在编译阶段产生的错误成为编译时错误(compile-time errors)或语法错误(syntax errors)。

常见的编译错误有放错分号的位置、方括号([])或花括号({})不匹配、拼写错误或字母大小写错误等。使用未声明的类也会导致此类错误发生,例如注释掉#import "CoreLocation.h",这时候ViewController.m的中间文件包括来自CoreLocation.h的代码,其中包括CLLOcationManager的接口声明和CLLocationManagerDelegate的协议声明,没有相应的导入语句,这些文件就不会成为所生成的中间文件的一部分,编译器也就无法处理相关的代码。


连接阶段:目标文件会包含(在实现文件中实现的)方法的机器码。但是某个实现文件可能hi用到其他实现文件的代码,例如Appdelegate.m会使用到startUpdatingLocation方法,该方法的机器码保存在CLLocationManger.m的目标文件中。编译器不会将startUpdatingLocation方法的代码拷贝至Appdelegate.m的目标文件中,而是设置一个连接,指向CLLocationManager.m的目标文件。连接二进制文件和库就是处理这类连接的阶段,该阶段简称为连接阶段

例如将Core Location框架和目标连接起来。框架是一组类的集合,类由两个文件定义:头文件和实现文件。框架的实现文件是已经预编译好的,并且框架回家创立后的目标文件分成一个或多个库文件(所以Objective-C的框架没有实现文件,相应地文件已转成机器码)。凡是用到Core Location框架代码的类,编译器都会在其目标文件中放置相应地连接,指向Core Location库。

如果编译器无法处理某个连接(例如无法找到包含相应代码的目标文件,或是目标文件没有包含被引用的代码),就会产生连接错误。例如在使用Core Location中的类时候没有引入CoreLocation.framework框架,就会出现连接错误的红色警告。


个人总结:这些编译过程方面的知识点很容易理解,但是往往被我们所忽视。所以在编码之余,拿出工具书看看理论讲解,肯定能够提高自己对于编码的理解。

  • 打赏
  • 点赞
  • 收藏
  • 分享
共有 人打赏支持
粉丝 183
博文 53
码字总数 49671
×
召唤攻城狮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: