Objective-C头文件无法将自定义对象识别为类型

时间:2011-10-25 22:02:42

标签: objective-c import compiler-errors

我正在使用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;),正如你们中的一些建议。

再次感谢!

3 个答案:

答案 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“”会发生什么。圆形引用可能有问题