大家好!我是深圳校区双元课堂的iOS导师--黄铁军。
因为在某一天带晚自习的时候,一位同学在做作业的时候遇到了一个类之间--循环依赖的问题,所以我想在这里和大家分享一下#import与@class。 OC中,当一个类使用到另一个类时,并且在类的头文件中需要创建被引用时的指针时, 如以下代码:
A.h文件 #import "B.h" @interface A : NSObject { B *_b; } @end
为了简单起见:A类是引用类,B类是被引用类,这里先不需要考虑A类的实现文件。
通常引用一个类有两种办法: 一种是通过 #import 方式引入;另一种是通过 @class 引入;
这两种的方式的区别在于: 1、#import 方式会包含被引用类的所有信息,包括被引用类的变量和方法;@class方式只是告诉编译器在 A.h 文件中 B *b 只是类的声明,具体这个类里有什么信息,这里不需要知道,等实现文件中真正要用到时,才会真正去查看B类中信息; 2、使用 @class 方式由于只需要只要被引用类(B类)的名称就可以了,而在实现类由于要用到被引用类中的实体变量和方法,所以需要使用 #import 来包含被引用类的头文件; 通过上面2点也很容易知道在编译效率上,如果有上百个头文件都 #import 了同一个文件,或者这些文件一次被 #import (A->B,B->C,C->D...),一旦最开始的头文件稍有改动,后面引用到这个文件的所有类都需要重新编译一边,这样的效率也是可想而知的,而相对来讲,使用 @class 方法就不会出现这种问题了。
对于循环依赖关系来说,比如A类引用B类,同时B类也引用A类 B类的代码:
B.h文件 #import "A.h" @interface B : NSObject { A *_a; } @end
这样子就出现类之间循环依赖引用了,这样子是不可以,编译就会出错。
B.h文件 @class A; @interface B : NSObject { A *_a; } @end
当使用 @class 声明的话,编译就不会出现错误。
由上可知,@class 是放在 interface 中的,只是在引用一个类,将这个被引用类作为一个类型,在实现文件中,如果需要引用到被引用类的实体变量或者方法时,还需要使用 #import 方式引入被引用类。
举个例子说明一下。 在 ClassA.h 中 #import ClassB.h 相当于#include整个.h头文件。如果有很多.m文件#import ClassA.h,那么编译的时候这些文件也会#import ClassB.h增加了没必要的#import,浪费编译时间。在大型软件中,减少.h文件中的include是非常重要的。
如果只是 ClassB 那就没有include ClassB.h。仅需要在需要用到ClassB的.m文件中 #import ClassB.h
那么什么时候可以用呢? 如果ClassA.h中仅需要声明一个ClassB的指针,那么就可以在ClassA.h中声明 @ClassB ... ClassB *pointer;
所以,一般来说,@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用的。 在实现这个接口的实现类中,如果需要引用这个类的实体变量或者方法之类的,还是需要import在@class中声明的类进来.
|