我try 过编译,但每次都有一个方法抛出一个奇怪的"expected a type"错误.我在标题中有一个方法:
-(ANObject *)generateSomethingForSomethingElse:(NSString *)somethingElse;
错误指向此方法的返回类型.我已经使用#import "ANObject.h"
将ANObject
导入到标题中,ANObject
可以编译..
为什么会这样?
我try 过编译,但每次都有一个方法抛出一个奇怪的"expected a type"错误.我在标题中有一个方法:
-(ANObject *)generateSomethingForSomethingElse:(NSString *)somethingElse;
错误指向此方法的返回类型.我已经使用#import "ANObject.h"
将ANObject
导入到标题中,ANObject
可以编译..
为什么会这样?
这与源文件的编译顺序有关.您可能已经知道,在定义方法之前不能调用它(请参见下面的伪代码):
var value = someMethod();
function someMethod()
{
...
}
这将导致编译时错误,因为尚未定义someMethod().阶级也是如此.类由编译器一个接一个地编译.
因此,如果你想象所有的类在编译之前都被放入一个巨大的文件中,你可能已经看到了这个问题.让我们看看Ship
和BoatYard
类:
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
再一次,因为Ship
类还没有定义,我们还不能引用它.解决这个问题非常简单;更改编译顺序并编译.我相信您熟悉XCode中的这个屏幕:
但是你知道你可以在列表中上下拖动文件吗?这会更改文件的编译顺序.因此,只要把Ship
级移到BoatYard
级之上,一切都很好.
但是,如果你不想这样做,或者更重要的是,如果两个对象之间存在循环关系,该怎么办?让我们通过添加对Ship
所在的当前BoatYard
的引用来增加该对象图的复杂性:
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) BoatYard* currentBoatYard;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
天啊,现在我们有麻烦了.这两者不能并排编译.我们需要一种方法来通知编译器Ship*类确实存在.这就是为什么@class
关键字如此方便.
用外行的话说,你是在说,"相信我,Ship
真的存在,你很快就会看到的.".总而言之:
@class Ship;
@interface BoatYard : NSObject
@property (nonatomic, retain) Ship* currentShip;
@end
@interface Ship : NSObject
@property (nonatomic, retain) BoatYard* currentBoatYard;
@property (nonatomic, retain) NSString* name;
@property (nonatomic, assign) float weight;
@end
现在,编译器在编译BoatYard
时知道,Ship
类定义很快就会出现.当然,如果不这样做,编译仍然会成功.
然而,@class
关键字所做的只是通知编译器该类很快就会出现.它是#import
的替代品.您仍然必须导入头文件,否则将无法访问任何类内部文件:
@class Ship
-(void) example
{
Ship* newShip = [[Ship alloc] init];
}
这无法工作,并且将失败,并显示一条错误消息,表明Ship是转发声明.完成#import "Ship.h"
后,就可以创建对象的实例.