18

我在一些我认为很简单的事情上遇到了一个非常奇怪的错误。

#import <Foundation/Foundation.h>
#import "ViewController.h"
#import "GameObject.h"


@interface GameController : NSObject 

@property (strong) GLKBaseEffect * effect;
@property (strong) NSMutableArray * gameObjects;
@property (strong) NSMutableArray * objectsToRemove;
@property (strong) NSMutableArray * objectsToAdd;


+ (GameController *) sharedGameController;
- (void) tick:(float)dt;
- (void) initializeGame: (ViewController*) viewcontroller;//ERROR: EXPECTED A TYPE

- (void) createObject:(Class) objecttype atPoint:(CGPoint)position;
- (void) deleteObject:(GameObject*) object atPoint:(CGPoint)position;
- (void) manageObjects;

@end

为什么会质疑“ViewController”是否是一种类型?这是一个我已经正确实现的类。它也被进口了。

编辑*

如果有帮助,这里是 ViewController.m 类。

#import "ViewController.h"

@implementation ViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    [[GameController sharedGameController] initializeGame:self];
}

@end

编辑 2 **

和 ViewController.h 文件

#import <GLKit/GLKit.h>
#import "GameController.h" 

@interface ViewController : GLKViewController

@end
4

2 回答 2

49

使用前向声明:@class ViewController;代替#import "ViewController.h". 在 Objective-C 的另一个头文件中通常不需要导入。

如果使用ViewControllerin GameController,则可以将导入添加到 GameController.m。

你可能有一个循环依赖。

定义循环依赖的基本方法是:

  • GameController.h进口ViewController.h
  • ViewController.h进口GameController.h

首先看到哪个取决于翻译中声明的顺序,但显然必须先出现一个,因为在这种情况下,标题不同意哪个必须先出现。

在真实的代码库中,您可能#import "ViewController.h"在许多源文件中。这会产生非常复杂的依赖关系。在 ObjC 中,这些依赖关系在很大程度上是不必要的——大多数时候您可以在标头中使用前向声明(这将缩短您的构建时间)。

所以我解释了最简单的情况,但是当 15 个标题时会发生什么#import ViewController.h?好吧,您必须跟踪哪个标头为该翻译引入了循环依赖。如果您没有很好地管理依赖项,那么您可能必须逐步检查数十个(或数百个)文件。有时,最简单的方法是查看该翻译的预处理输出(例如,有问题的*.m文件)。如果依赖关系没有被最小化,那么输出可能是数十万行(如果管理得当,您的构建时间可能会快 20 倍或更多倍)。因此,在大型代码库中定位循环依赖的复杂性会迅速上升;你#import#include标题越多。在标头中使用前向声明(如果可能)解决了这个问题。

例子

因此,鉴于您在 OP 中的标题,您可以将其重写为:

游戏控制器.h

// includes
#import <Foundation/Foundation.h>

// forwards required by this header    
@class GameObject;
@class GLKBaseEffect;
@class ViewController;

// header declarations
@interface GameController : NSObject 

@property (strong) GLKBaseEffect * effect;
@property (strong) NSMutableArray * gameObjects;
@property (strong) NSMutableArray * objectsToRemove;
@property (strong) NSMutableArray * objectsToAdd;


+ (GameController *) sharedGameController;
- (void) tick:(float)dt;
- (void) initializeGame: (ViewController*) viewcontroller;//ERROR: EXPECTED A TYPE

- (void) createObject:(Class) objecttype atPoint:(CGPoint)position;
- (void) deleteObject:(GameObject*) object atPoint:(CGPoint)position;
- (void) manageObjects;

@end

游戏控制器.m

#import "GameController.h"
#import "ViewController.h" // << if you need it in this source
#import "GameObject.h" // << if you need it in this source

@implementation GameController
...

然后,您可以对 ViewController.h(正在导入 GameController.h)应用相同的处理。

于 2013-07-12T22:22:55.617 回答
0

你确定里面定义的类接口ViewController.h也拼写为“ ViewController”吗?

我通过ViewController.h在我的项目中创建一个类进行了快速测试,但将接口重命名为ViewControllers内部并得到与您相同的错误。

于 2013-07-12T22:27:26.407 回答