2: 在类的头文件中尽量少引用其他头文件

2017-04-10  本文已影响137人  KKLinJJ

与C、C++一样,Objective-C也使用“头文件”和“实现文件”来区隔代码。用Objective-C语言编写类的标准方式:以类名做文件名,分别创建2个文件,头文件后缀.h,实现文件.m
用Objective-C语言编写任何类几乎都需要引入Foundation.h,如果不在该类本身引入这个文件的话,那么就要引入与其超类所属框架相对应的"基本头文件"


使用向前声明延后引入头文件时机

比如存在CWGPerson类和CWGEmployer类。
每个CWGPerson实例都应该有一个CWGEmployer.
于是我们一般会这样写:(直接在.h中引入头文件)

#import "CWGEmployer.h" 
@interfance  CWGPerson : NSObject 
@property (nonatomic, strong) CWGEmployer *employer; 
@end 

这样做不是不行,只是不够优雅罢了.因为在编译一个使用了CWGPerson类的文件时,不需要知道CWGEmployer类的全部细节,只需要知道有一个类名CWGEmployer就可以了.于是我们还可以这样写:

//类CWGPerson头文件
@class CWGEmployer
@interfance  CWGPerson : NSObject
@property (nonatomic, strong) CWGEmployer *employer;
@end

CWGPerson.m实现文件中则需要引入CWGEmployer类的头文件,因为使用的时候,则必须知道其所有的细节.

//类CWGPerson实现文件
#import "CWGPerson.h"
#import "CWGEmployer.h"
@implementation CWGPerson
// Implementation of methods
@end

将引入头文件的时机尽量延后, 只在确有需要时才真正引入,这样可以减少类的使用者所需引入头文件的数量.假如把CWGEmployer.h引入到CWGPerson.h中,那么只要引入CWGPerson.h,就会引入CWGEmployer.h的全部内容.如此持续下去,则要引入很多根本用不到的内容,还增加了编译时间.

例如CWGEmployer.m中增加了方法:

如果CWGPerson和CWGEmployer,都将彼此头文件引入到自己头文件中,这时候编译CWGEmployer,编译器必须知道CWGPerson这个类,而要编译CWGPerson,又必须知道CWGEmployer.这时候就会导致"循环引用".虽然使用#import不会导致死循环(#include会),但是这意味着2个类有一个是无法编译成功的。
分析:当类A引用类B,类B又需要引用类A的时候,如果我们都在.h头文件中引用对方的头文件,那么就会出现头文件循环引用的问题,实际上使用#import而非#include指令虽然不会导致死循环,但却意味着两个类中有一个无法被正确编译而报错。

相互引入头文件导致编译报错

解决方案:(目的是实现两个文件编译时刻不在相互引用对方)
1.在其中一个类.h头文件使用@class关键字向前声明另一个类,在该类.m文件中再使用#import引入头文件,另一个类正常引用就行。
2.在两个类的.h头文件中均使用@class,在两个类的.m实现文件中再使用#import引入对应的头文件。

一些必须引入头文件的情况
有些时候必须引入头文件:
1.该类继承了某个超类,则必须引入定义那个超类的头文件。
2.该类遵循某协议,也要引入该协议对应的头文件

如果你写的类继承某个超类,则必须引入定义那个超类的头文件.
如果要声明你写的那个类遵从某个协议(protocol),那么该协议必须有完整的定义.且不能使用"向前声明".因为"向前声明"只能告诉编译器有这么个协议,但是编译器这时要知道这个协议中定义的方法.例如:

#import "CWGShape.h"
#import "CWGDrawable.h"
@interface CWGRectangle : CWGShape  <CWGDrawable>
@property (nonatomic, assign) CGFloat width;  ///< 宽
@property (nonatomic, assign) CGFloat height; ///< 高
@end

其中#import "CWGDrawable.h"是难免的.

#####总结:

* 除非确有必要,否则不要引入头文件.一般说来,应该在某个类的头文件中使用"向前声明"来提及别的类.并在实现文件中引入那些类的头文件,这样做可以尽量降低类之间的耦合性.

* 有时无法使用"向前声明",比如某个类要遵从某个协议,这种情况下,尽量把"该类遵循某协议"的声明移至到"延展"中(class - continuation 分类).如果还不行,就把协议单独放在一个头文件中,然后将其引入.
上一篇下一篇

猜你喜欢

热点阅读