可能重复:
@class vs. #import
在.h文件中,您可以使用
添加要查看的类(不知道这是什么正确的术语)#import "SomeClass.h"
或改为使用
@class SomeClass;
我尝试了两种方法,但它们都有效。有什么不同?我应该使用其中一种方法而不是其他方法吗?什么是最佳做法?
答案 0 :(得分:11)
#import
包含源代码中标头的内容。
因此,也导入了导入标题中的每个声明。
@class
仅向编译器声明给定的类存在,但不导入标头本身。它被称为前向声明,因为您只向编译器声明该类存在之前详细定义它(告诉它实现了哪些方法等等)
后果:
#import
文件中使用.m
时,如果修改了标头,则会在下次编译时触发.m
#import
文件的重新编译。相反,如果您使用@class
,则.m
不依赖于标头,如果修改了标头,则不会重新编译.m
文件。@class
也可以避免交叉导入,例如如果A类引用了B类而B类引用了A类,那么在同一时间内你不能在Ah中的Bh 和 #import "A.h"
中#import B.h
(它将是一个“import infinite loop”)@class
只声明一个类存在,并且不告诉编译器该类响应的方法。这就是为什么通常最好的做法是在引用类A 的头文件(.h)中使用@class A
转发声明类,只是为了让编译器知道“A”是一个已知类,但不需要在实现(.m)文件中了解更多,和#import "A.h"
,以便您可以在A类的对象上调用方法你的源文件。
除了避免导入循环外,这还可以避免在不需要的情况下重新编译文件,从而减少编译时间。
唯一的例外是当类的声明继承另一个类,或者它声明它符合给定的@protocol
(如委托协议等)时,因为在这种特殊情况下,编译器需要您要#import
父类的整个定义或@protocol
(以了解您的类是否正确符合此给定的协议)。
MyClassA.h
// Tells the compiler that "MyClassB" is a class, that we will define later
@class MyClassB; // no need to #import the whole class, we don't need to know the whole definition at this stage
@interface MyClassA : NSObject {
MyClassB* someB; // ok, the compiler knows that MyClassB is a class, that's all it needs to know so far
}
-(void)sayHello;
-(void)makeBTalk;
@end
MyClassB.h
@class MyClassA; // forward declaration here too
// anyway we couldn't #import "MyClassA.h" here AND #import "MyClassB.h" in MyClassA.h as it would create an unsolvable import loop for the compiler
@interface MyClassB : NSObject {
MyClassA* someA; // ok, the compiler knows that MyClassA is a class, that's all it needs to know so far
}
-(void)talk;
-(void)makeABePolite;
@end
MyClassA.m
// import MyClassB so that we know the whole definition of MyClassB, including the methods it declares
#import "MyClassB.h" // thus we here know the "-talk" method of MyClassB and we are able to call it
@implementation MyClassA
-(void)sayHello { NSLog(@"A says Hello"); }
-(void)makeBTalk {
[someB talk];
// we can call the 'talk' method because we #imported the MyClassB header and knows this method exists
}
@end
MyClassB.m
// import MyClassA so that we know the methods it declares and can call them
#import "MyClassA.h"
@implementation MyClassB
-(void)talk { NSLog(@"B is talking"); }
-(void)makeABePolite {
[someA sayHello];
// we can call this because we #import MyClassA
}
@end
PS:请注意,如果这是一个最佳实践,我知道很多开发人员(包括我自己有时^^){。1}}他们的.h文件中需要的标头,而不是只有前进-declare它使用#import
...这是一个坏习惯 - 或者因为这些开发人员不知道这些微妙之处 - 不幸的是你会在现有代码中遇到。
答案 1 :(得分:0)
使用@class称为前向声明。由于通常您不需要知道.h文件中类的具体细节,因此通常只需要这些。
转发声明可防止您进入导入特定.h文件的情况,该文件表示要导入另一个.h文件,该文件表示再次导入原始.h文件,依此类推。
答案 2 :(得分:0)
@class
转发声明允许您使接口的行为类似于接口。含义:声明您的代码。
但这并不意味着您可以省略#import
声明。您刚刚将责任转移到导入并使用它的实现。
基本上,由于您没有在当前标头中导入任何其他标头,因此可以将其视为性能提升。
重要说明:当您使用代理时,情况并非如此。
如果您正在使用委托,则必须具有适当的#import
语句,以便编译器知道该类将实现哪些委托方法。
您可能还想查看以下SO问题:@class vs. #import