Заголовочный файл Objective-C, не распознающий пользовательский объект как тип - PullRequest
23 голосов
/ 26 октября 2011

Я работаю над игрой для iPad, использующей cocos2d, которая включает в себя доску, заполненную различными типами плиток.Я создал собственный класс с именем 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, поскольку он не нужен в заголовочном файле. Позже, если я решу использовать Board в файле Tile.h, я буду использовать прямые ссылки (@class Board;), как некоторые из вас предложили.

Еще раз спасибо!

Ответы [ 3 ]

64 голосов
/ 26 октября 2011

Это классическая проблема с заголовками, импортирующими заголовки. У вас есть круг: 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.

Это гарантирует компилятору, что существует класс с именем Tile, который будет существовать во время выполнения; затем вы можете обратиться к этому имени в оставшейся части вашего заголовка. В вашей реализации для Board вы импортируете Tile.h. Это позволит компилятору видеть методы и свойства, связанные с классом Tile, где они необходимы.

Аналогично, переместите #import "Board.h" в Tile.m. Поскольку вы не ссылаетесь на класс Board в Tile.h, вам не нужно делать предварительное объявление.

В общем, лучше всего импортировать заголовки классов только в файлы реализации, где они необходимы. Заголовки фреймворка, поскольку они никогда не вызовут цикл с вашим кодом, могут и - поскольку вам нужно ссылаться на многие из объявленных в них классов - должны быть импортированы в ваши заголовки.

6 голосов
/ 26 октября 2011

Два файла не могут импортировать друг друга.Вам необходимо переместить директивы импорта в файлы реализации, и вместо этого просто forward-Объявление классов в заголовках (например, @class Tile; в Board.h).

Причина циклического импортане работает, потому что #import буквально включает текст из импортированного файла на месте.Но это также гарантирует, что текст из файла будет включен только один раз, чтобы избежать дублирования объявлений.Поэтому, когда Tile.h говорит, что текст из Board.h должен идти перед ним, а Board.h говорит, что текст из Tile.h должен идти перед ним, компилятор буквально ничего не может сделать - один из них должен идтиво-первых, и этот файл будет жаловаться, потому что ожидал, что другой уже будет там.

0 голосов
/ 26 октября 2011

Это может не быть проблемой, но что произойдет, если вы удалите "#import" Board.h "" из файла Tile.h. У вас могут быть проблемы с циклическими ссылками

...