在 .m 文件和 .h 文件中,使用 #import 有什么异同?

361 阅读2分钟
1、都写在.h的时候,有时候会产生循环引用的问题,导致编译不过。
2、写在.h的时候,当有其他类引用了该.h文件,它会递归引用.h上引用的.h,导致编译文件变大,编译时间会变长。
3、.h的改动,会导致引用了该.h的文件都触发重新编译。所以建议.h文件中尽量少地引用其他.h。减小改动.h带来的增量编译范围。

产生循环引用的问题,导致编译不过

A类倒入B类

#import <Foundation/Foundation.h>
#import "B.h"

NS_ASSUME_NONNULL_BEGIN

@interface A : NSObject

@end

NS_ASSUME_NONNULL_END

#import "A.h"

@implementation A

@end

B类倒入A类

#import <Foundation/Foundation.h>
#import "A.h"

NS_ASSUME_NONNULL_BEGIN

@interface B : NSObject

@end

NS_ASSUME_NONNULL_END

#import "B.h"

@implementation B

@end

C类继承A类

#import "A.h"

NS_ASSUME_NONNULL_BEGIN

@interface C : A

@end

NS_ASSUME_NONNULL_END

#import "C.h"

@implementation C

@end

一切,OK,编译通过

如果让B类也继承A类

#import <Foundation/Foundation.h>
#import "A.h"

NS_ASSUME_NONNULL_BEGIN

@interface B : A

@end

NS_ASSUME_NONNULL_END

这时候编译器报错了,"Cannot find interface declaration for 'A', superclass of 'B'"

问题在于A中import了B.h,而B又引用了A,这就构成了交叉引用。不过编译器却给出了一个让人混淆不清的提示“找不到父类接口”。

导致编译文件变大,编译时间会变长

在.h头文件中,尽量少的去引入其他的类或库,多使用@class,@protocol这种前置声明,然后在实现文件中真正用到类结构时再#import,前置声明可以最小化依赖关系.

比如有A,B,C三个类,如果在B.h中导入了C.h,A.h中导入了B.h,那么当C.h中有修改,则A,B,C三个.m实现文件都需要重新编译,但实际上A与C之间并不需要引用,所以此时在B.h中应该对C作前置声明,在B.m中在导入,这样当C.h改变时,只会影响真正使用到得B.m,节约了编译时间