您的位置:首页 > 移动开发 > Objective-C

OC学习日记Day2:#include、#import和@class的工作原理

2016-04-13 11:43 726 查看

OC学习日记Day2:#include、#import和@class的工作原理

呆萌萌的#include

我们在用#include导入头文件时,头文件里一般都会加上以下代码

#ifndef __XIXI_H
#define __XIXI_H
...
#endif


在这段代码中,先用#ifndef判断(if no define)是否定义了__XIXI_H。如果没有定义,那么就#define 定义一个__XIXI_H。当你的头文件定义完成之后,就用#endif 结束了第一行的if判断。

显然这段代码的作用是为了防止重复定义头文件里面的一些变量和方法。那么,我们为什么要如此麻烦地在每一个头文件中都要做这样的判断呢?

int i;
int i;


在这个代码段中,只做了一件事,就是定义了两次整数类型的标识符(名字)为i的变量。这样重复定义的做法是编译器所不允许的。而恰恰在我们使用#include进行头文件导入时,会导致大量的致命的重复定义。例如:有A.h、B.h、C.h和D.h这四个头文件。

在A.h中有
int a;


在B.h中有

#include "A.h"
int b;


在C.h中有

#include "A.h"
int c;


在D.h中有

#include "B.h"
#include "C.h"
int d;


那么在编译器最终编译D.h头文件时,D.h实际的代码是

//处理#include "B.h" 将B.h里面的代码复制粘贴过来
#include "A.h" int b;
//处理#include "C.h" 将C.h里面的代码复制粘贴过来
#include "A.h" int c;
//这里是D.h 自己定义的
int d;


当编译器处理到这里时,问题还没那么明显,但不代表没有问题。因为编译器还没有工作完,还有两个#include “A.h”要处理

//处理#include "B.h" 将B.h里面的代码复制粘贴过来
//处理#include "A.h" 将A.h里面的代码复制粘贴过来
int a;
int b;
//处理#include "C.h" 将C.h里面的代码复制粘贴过来
//处理#include "A.h" 将A.h里面的代码复制粘贴过来
int a;
int c;
//这里是D.h 自己定义的
int d;


当编译器处理完所有的#include之后发现,在D.h定义了两次int a。故而出现重复定义错误。而错误的原因在于呆萌萌的#include会将头文件中的变量和方法直接复制粘贴过来。而在D.h处理了两次#include “A.h”。便将int a;直接复制粘贴了两次。所以为了避免这个问题,我们必须在.h头文件中加入#ifndef判断,告诉呆萌萌的#include,如果这个头文件的代码你已经复制粘贴过一次了就不要重复粘贴复制了。

路痴#import

虽然在.h头文件中加入#ifndef判断可以避免呆萌萌的#include不要重复粘贴复制。但对于程序员来说,要在每一个.h头文件中加入#ifndef判断显得有些繁琐。而使用#import可以改善这个问题。

#import可以说是#include的优化。在使用#import时,它会自己先检查之前是否已经导入过这个头文件,如果检查发现已经包含了这个头文件了就不会重复导入了。对于上面A.h、B.h、C.h和D.h将#include替换成#import,可以发现不用加#ifndef判断也可以编译成功。

相对于#include的直接将定义复制粘贴过来,#import则是告诉编译器自己去这个头文件找相关的定义。但是,不幸的时#import是一个路痴,使用#import可能会造成交互问路的情况。例如:有A.h和B.h文件。

在A.h 中有:
#import "B.h"


在B.h 中有:
#import "A.h"


如果这两个头文件只是#import相互的头文件,没有调用对方定义的数据,这时编译还是可以通过的。但请记住,编译通过不代表代码没有错误。

现在在A.h中加入一行代码

#import "B.h"
//加在@interface和@end之间哦
@property(nonatomic) B *b;


这时就会出现错误提示了:Unknown type name ‘B’; did you mean ‘A’? 编译器抱怨说,我找不到B。可是我们明明#import了B.h头文件了,而class B 就是定义在B.h头文件当中,那为什么编译器说找不到class B呢?原因就是在于:程序存在相互问路的无解循环。当在A.h中执行#import “B.h”时,编译器就屁颠屁颠跑去B.h去找class B。可是因为B.h中又执行了#import “A.h”,于是编译器又被告知去”A.h”里面找class B。就这样,不管编译器去哪个头文件,都被告知去另一个头文件。反反复复永远找不到class B。所以当头文件使用#import相互导入时,就会陷入无解的问路循环当中。#import路痴得太严重!那怎么办呢?得找小不低@class来帮忙了。

小不点@class

当头文件中使用了@class的时候,@class就会告诉编译器,那个#import是个路痴,别老是听它瞎忽悠。你要找的什么我告诉你就行了。现在我也只是知道你要找的就是一个类,但具体是这个类是什么,会做什么我也不清楚。但你也不用着急,你就知道你要找的是一个类就行了。这样,编译器就不会被#import忽悠来忽悠去地问路了。

现在在A.h中加入@class:

#import "B.h"
//编译器,别听#import忽悠了,B就是一个类。知道这个就行了
@class B;
//加在@interface和@end之间哦
@property(nonatomic) B *b;


一些注意

a. 在使用#include或#import时有<>和”“两种方式。其中<>是在导入别人提供给你的头文件时使用的。例如
#import <Foundation/Foundation.h>
。这个Foundation.h就是苹果公司提供的。而”“是在导入自己的头文件时使用的。例如
#import "B.h"
。这个B.h就是自己定义的。

b. Objective-C没有命名空间。这个命名空间可以理解成一个归类,你使用的所有头文件都没有帮你归类,都放在一起了。Objective-C并没有帮你区分这是你写的头文件还是别人写得头文件。所以你使用的头文件一旦出现重名,就会出现类名冲突。为此,我们在命名类名时,苹果公司推荐加上一些有代表性的字母做前缀。例如公司名字的缩写。所以对于上面的A、B、C和D这样的命名是不规范的,应该加上一些标志性的前缀。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  objective-c