我正在使用cocos2d开发一款适用于iPad的游戏,其中包含一块充满不同类型瓷砖的电路板。我创建了一个名为Tile
的自定义类作为tile的常规模板和一些具有不同属性和方法的Tile
子类。我还创建了一个名为Board
的类,除其他外,它使用特殊的坐标系跟踪所有图块的位置。
出于某种原因,在Board
类中,编译器似乎没有将Tile
识别为一种对象,即使我在顶部添加了#import "Tile.h"
的文件。
以下是相关代码(只是询问您希望看到代码的其他部分):
Tile.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Board.h"
@interface Tile : NSObject
-(void) updateNeighbors;
@property (nonatomic, retain) CCSprite* sprite;
@property (assign) CGPoint coords;
@property (assign) CGPoint positionInPoints;
@property (nonatomic, retain) NSMutableArray *neighbors;
@end
Board.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "Tile.h"
@interface Board : NSObject
+(Board*)sharedBoard;
- (void) putTile: (Tile*) tile AtIndex: (CGPoint) index; //<-- error here!
- (void) replaceTileAtIndex: (CGPoint) index1 WithTileAtIndex: (CGPoint) index2;
- (Tile*) tileAtIndex: (CGPoint) index; //<-- error here!
- (void) populate;
@property (nonatomic, retain) NSMutableArray *tiles;
@property (nonatomic, retain) NSString *type;
@property (assign) CGPoint size;
@end
此代码甚至不会构建,我收到以下错误:
预期'('在'Tile'之前'
如果我将类型从(Tile*)
更改为(NSObject*)
,则会修复错误,这会让我相信Tile
未被识别为某种对象。
我通过Google和这个网站进行了搜索,但无法弄清楚为什么会发生这种情况。
正如大家都指出的那样,问题是这两个头文件是相互导入的,这是不允许的。现在,我通过将#import“Board.h”语句移动到Tile.m来解决问题,因为头文件中不需要它。稍后,如果我决定在Tile.h文件中使用Board,我将使用前向引用(@class Board;),正如你们中的一些建议。
再次感谢!
答案 0 :(得分:64)
这是标头导入标头的典型问题。你有一个圆圈:Tile.h导入Board.h,导入Tile.h.这会混淆编译器 - 它会陷入循环中。
您可以通过不将标头导入标头来解决此问题。但是,您仍然需要让编译器知道Tile
。在Board.h中,创建一个类"forward declaration":
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@class Tile; // Dear compiler,
// Tile is a class that I will need to refer
// to in this file. Please consider it to be a
// type; I promise it'll be defined at runtime.
// Sincerely, stephenalexbrowne
@interface Board : NSObject
//etc.
这可以确保编译器在运行时存在一个名为Tile
的类;然后,您可以在标题的其余部分中引用该名称。在Board
的实现中,导入Tile.h.这将让编译器看到与Tile
类相关的方法和属性。
同样,将#import "Board.h"
移至Tile.m.由于您没有在Tile.h中引用Board
类,因此您无需进行前瞻性声明。
通常,最好只将类标题导入需要它们的实现文件中。框架标题,因为它们永远不会导致代码循环,并且 - 因为您需要引用其中声明的许多类 - 应该导入到标题中。
答案 1 :(得分:6)
两个文件无法互相导入。您需要将导入指令移动到实现文件,而只需转发声明标题中的类(例如Board.h中的@class Tile;
)。
循环导入不起作用的原因是因为#import
字面上包含来自导入文件的文本。但它也确保文件中的文本只包含一次,以避免重复声明。因此,当Tile.h说Board.h中的文本需要在它之前时,并且Board.h说Tile.h中的文本需要在它之前进行,所以编译器几乎没有什么可以做的 - 其中一个需要去首先,该文件会抱怨,因为它期待另一个文件已经存在。
答案 2 :(得分:0)
这可能不是问题,但是如果从Tile.h文件中删除“#import”Board.h“”会发生什么。圆形引用可能有问题