一、#import和#include的区别
1.#include:相信我们学C/C++时候是引入头文件用习惯了#include,但是#include的最大缺点就是引用的文件可以被多次引用),这样就陷入了递归包含。
比如:class文件A、B都引用了class C,如果class D引用了class A、B,这时候编译通过,链接就会报重复引用的错误,因为相当于class D引用了两次class C
2.#import:为了解决递归包含问题,优化的#include。确保了引用的文件只会被引用一次。
二、@class的引入(又叫”向前声明“)
1.什么是@class:
@class不像#import那样链入该头文件的全部信息(包括实例变量和方法等)而是让别人只需要知道它是个类名,不需要知道细节
2.为什么要引入@class:
(1)解决相互依赖(相互包含)问题。
当即系其中一个头文件是编译器发现他引入了另一个头文件,而那个头文件有引用了第一个头文件,如果用#include会导致死循环,用#import会意味着其中一个类无法正确被编译。
例:
// Man.h
#import<Foundation/Foundation.h>
// import会链入该头文件的全部信息 ,包括实例变量和方法等
#import "Women.h"
//只告诉编译器Women是类名称,不需要知道实例变量和方法等
//@class Women;
@interface Man : NSObject{
@public
Women *_women;
}
-(void)love;
@end
// Man.m
#import "Man.h"
#import "Women.h"
@implementation Man
-(void)love{
[_women walk];
}
@end
// Woman.h
#import<Foundation/Foundation.h>
#import "Man.h"
@interface Women : NSObject{
Women *_women;
}
-(void)walk;
@end
// Woman.m
#import "Women.h"
@implementation Women
- (void)walk{
NSLog(@"walk together");
}
@end
main.m
#import<Foundation/Foundation.h>
#import "Women.h"
#import "Man.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
//Women.h和Man.h相互导入会出现问题
//这时候我们就可以使用@class解决这样的问题
//我们一般在.h文件中使用@class,因为在.h文件中一般是不会使用类的属性和方法的
//在.m文件中可以导入.h文件
Man *man =[[Man alloc] init];
Women *women = [[Women alloc] init];
man->_women= women;
[man love];
}
return 0;
}
如果这时候run会报错,我们可以看一下报错内容(Xcode Version 8.2.1)。
报错报错是未知的类型名称Woman,不过我们明明都有,再仔细看一下报错内容是文件既包括在Women中,又包括在main中。
//如果我们把Man.h中的代码改成向前声明就OK了
#import<Foundation/Foundation.h>
//#import "Women.h"
@class Women;
@interface Man : NSObject{
@public
Women *_women;
}
-(void)love;
@end
(2)对于编译效率而言
假设有500个文件都#import了同一个头文件或依次引用(a->b,b->c,c->d.....),如果最开始的那个头文件有变化(例如a)那么所有后边的所有引用的类都需要重新编译,这样就会耗费大量时间,用@class则不会。
(3)一般来说@class是放在interface中的,只是为了在interface中引用这个类,把这个类作为一个类型来用,在实现这个接口的类中,如果需要引用这个类的实体变量或者方法之类的,还是需要@import在@class中声明的类来0。
(4)可以尽量降低类之间的耦合
网友评论