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

ste*_*wne 23 import compiler-errors objective-c

我正在使用cocos2d开发一款适用于iPad的游戏,其中包含一块充满不同类型瓷砖的电路板.我创建了一个自定义类,称为Tiletile的通用模板,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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

此代码甚至不会构建,我收到以下错误:

预期'('在'Tile'之前'

如果我将类型更改(Tile*)(NSObject*),则会修复错误,这会让我相信Tile不会被识别为一种对象.

我通过谷歌和这个网站进行了搜索,但无法弄清楚为什么会这样.


更新

愚蠢的错误; 容易修复.

正如大家都指出的那样,问题是这两个头文件是相互导入的,这是不允许的.现在,我通过将#import"Board.h"语句移动到Tile.m来解决问题,因为头文件中不需要它.稍后,如果我决定在Tile.h文件中使用Board,我会使用前向引用(@class Board;),正如你们中的一些建议的那样.

再次感谢!

Jos*_*ell 64

这是标头导入标头的典型问题.你有一个圆圈:Tile.h导入Board.h,导入Tile.h. 这会混淆编译器 - 它会陷入循环中.

您可以通过不将标头导入标头来解决此问题.但是,您仍然需要让编译器知道Tile.在Board.h中,进行类的"前向声明":

#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.
Run Code Online (Sandbox Code Playgroud)

这可以确保编译器Tile在运行时存在一个被调用的类; 然后,您可以在标题的其余部分中引用该名称.在您的实现中Board,您导入Tile.h. 这将让编译器看到与Tile需要它们的类相关的方法和属性.

同样,移动#import "Board.h"到Tile.m. 由于您没有Board在Tile.h中引用该类,因此您无需进行前向声明.

通常,最好只将类标题导入需要它们的实现文件中.框架标题,因为它们永远不会导致代码循环,可以 - 并且 - 因为您需要引用其中声明的许多类 - 应该导入到标题中.


Chu*_*uck 6

两个文件无法互相导入.您需要将导入指令移动到实现文件,而只是在标头中向前声明类(例如@class Tile;在Board.h中).

循环导入不起作用的原因是因为#import字面上包含来自导入文件的文本.但它也确保文件中的文本只包含一次,以避免重复声明.因此,当Tile.h说Board.h中的文本需要在它之前时,并且Board.h说Tile.h中的文本需要在它之前进行,所以编译器几乎没有什么可以做的 - 其中一个需要去首先,该文件将抱怨,因为它期待另一个已经存在.