当我使用以下代码编译时,没有错误:
@class RootViewController;
//#import "RootViewController.h"
Run Code Online (Sandbox Code Playgroud)
当我使用以下代码编译时,我收到一个错误:
//@class RootViewController;
#import "RootViewController.h"
Run Code Online (Sandbox Code Playgroud)
"错误:'RootViewController'之前的预期说明符 - 限定符列表"
我不明白两者之间的区别是什么,因为我在类似的类中使用了#import并且编译时没有错误!
mip*_*adi 25
@class当您需要知道特定文件中的类的名称时使用,但您不需要知道有关该类的任何详细信息(例如,其方法).#import当你真正需要使用该类时使用(即,发送消息).
例如,如果要在头文件中声明实例变量,则可以使用@class声明某种类型的实例变量:
@class MyOtherClass;
@interface MyClass : NSObject
{
MyOtherClass *myIvar;
}
@end
Run Code Online (Sandbox Code Playgroud)
由于您还没有使用myIvar,除了类型MyOtherClass存在外,您不需要了解它.
然而:
#import "MyOtherClass.h"
- (void)doSomething
{
[myIvar doSomethingElse];
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您将doSomethingElse消息发送给myIvar; 编译器需要知道MyOtherClass定义此方法的实例,因此您必须导入头文件或编译器会抱怨.
为什么要担心这个?
它主要与依赖关系有关.当您#import将A文件B存入文件B时,文件B 依赖于文件A - 也就是说,如果文件A发生更改,则必须重新编译文件B.如果@class在文件B中使用,则文件B不依赖于文件A,因此,当文件A更改时不需要重新编译 - 因此,如果您只是声明一个类型而不是实际上依赖于文件A的实现,则可以通过不使用#import文件A 来节省编译时间.
我决定参考文档,因为我仍然感到困惑:
#进口
该指令与#include相同,只是它确保同一个文件永远不会包含多次.因此,它是首选的,并且在基于Objective-C的文档中的代码示例中用于代替#include.
此约定意味着每个接口文件间接包含所有继承类的接口文件.当源模块导入类接口时,它将获取构建该类的整个继承层次结构的接口.
@类
像这样的声明只是使用类名作为类型,并且不依赖于类接口的任何细节(它的方法和实例变量),@ class指令给编译器足够的预警预期.但是,在实际使用类的接口(创建实例,发送消息)的情况下,必须导入类接口.
基本规则:@class在头文件和#import实现文件中使用.(但是,你需要#import你的类'超类.在其他情况下你还需要在标题中使用`#import'.)
#import不等于#include.如果一个文件included多次,它将每次加载,但是对于许多#imports相同的文件,它仍然只会被加载一次.
因此,使用的主要原因@class不是为了避免循环依赖,而是为了使编译更快.
这是你必须使用的一个例子@class
//MYControl.h
@class MYControl; // Must use class
@protocol MYControlDelegate
-(void)control:(MYControl *)control didChangeToState:(UIControlState)state;
@end
@interface MYControl : UIControl
{
id<MYControlDelegate> delegate_;
}
@property (nonatomic, assign) id<MYControlDelegate> delegate;
@end
//MYControl.m
@implementation MYControl
@synthesize delegate = delegate_;
. . .
Run Code Online (Sandbox Code Playgroud)
在这种情况下,没有要导入的内容,因为委托协议在头文件中的主类上面声明.但是你仍然需要能够引用尚未声明的主类.那么@class只要让编译器知道有一些被调用的类MYControl并且将在某个时刻定义,它是什么呢?(但不是在运行时.该类将在编译过程中定义.)
编辑:从Objective-C手册:
因为像这样的声明只是使用类名作为类型而不依赖于类接口的任何细节(它的方法和实例变量),所以@class指令给编译器足够的预警预期.但是,在实际使用类的接口(创建实例,发送消息)的情况下,必须导入类接口.通常,接口文件使用@class来声明类,相应的实现文件会导入它们的接口(因为它需要创建这些类的实例或向它们发送消息).
@class指令最小化了编译器和链接器看到的代码量,因此是给出类名前向声明的最简单方法.简单,它避免了导入导入其他文件的文件时可能出现的潜在问题.例如,如果一个类声明另一个类的静态类型实例变量,并且它们的两个接口文件相互导入,则这两个类都不能正确编译.
请注意,在最后一句中提到了循环性,作为使用中处理的一般问题类中的一个@class.
| 归档时间: |
|
| 查看次数: |
6238 次 |
| 最近记录: |