目标C - 错误:'预期类型'

时间:2023-02-05 22:43:14

I'm getting a very strange error on something that I would have thought to be simple.

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

#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

Why would it question whether or not 'ViewController' is a type? It's a class that I've correctly implemented. It has also been imported.

为什么会质疑'ViewController'是否是一个类型?这是我正确实施的课程。它也被导入了。

EDIT *

编辑*

Here is the ViewController.m class if it helps.

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

#import "ViewController.h"

@implementation ViewController

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

@end

EDIT 2 **

编辑2 **

and the ViewController.h file

和ViewController.h文件

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

@interface ViewController : GLKViewController

@end

2 个解决方案

#1


34  

Use a forward declaration: @class ViewController; in place of #import "ViewController.h". The import is usually unnecessary in another header in Objective-C.

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

If you use ViewController in GameController, then you can add the import to GameController.m.

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

You probably have a circular dependency.

您可能有循环依赖。

The basic way to define a circular dependency is:

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

  • GameController.h imports ViewController.h
  • GameController.h导入ViewController.h
  • ViewController.h imports GameController.h
  • ViewController.h导入GameController.h

Which one will be seen first depends on the order of declaration in the translation, but obviously one will have to come first because in this case the headers disagree as to which must come first.

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

In a real codebase, you may #import "ViewController.h" in many source files. This creates very complex dependencies. These dependencies are largely unnecessary in ObjC -- you can use forward declarations most of the time in a header (and it will improve your build times).

在实际的代码库中,您可以在许多源文件中#import“ViewController.h”。这会创建非常复杂的依赖项。在ObjC中,这些依赖项基本上是不必要的 - 您可以在标题中大部分时间使用前向声明(并且它将改善您的构建时间)。

So I explained the simplest case, but what happens when 15 headers #import ViewController.h? Well, you would have to track down which header is introducing that circular dependency for that translation. If you don't manage dependencies well, then you may have to step through dozens (or hundreds) of files. Sometimes, it's easiest to just review the preprocessed output for that translation (e.g. the offending *.m file). If dependencies are not minimized, that output could be hundreds of thousands of lines (and your build times could be 20 or more times faster if it were managed correctly). So the complexity of locating circular dependencies quickly goes up in large codebases; the more you #import and #include in the headers. Using forward declarations in headers (where possible) solves this problem.

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

Example

So given your header in the OP, you could rewrite it as:

因此,考虑到OP中的标题,您可以将其重写为:

GameController.h

GameController.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

GameController.m

GameController.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
...

Then you can apply the same treatment to ViewController.h (which is importing GameController.h).

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

#2


0  

Are you certain that the class interface defined inside ViewController.h is also spelled as "ViewController"?

您确定ViewController.h中定义的类接口也拼写为“ViewController”吗?

I did a quick test by creating a ViewController.h class in my project, but renamed the interface to ViewControllers inside it and got the same error as you.

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

#1


34  

Use a forward declaration: @class ViewController; in place of #import "ViewController.h". The import is usually unnecessary in another header in Objective-C.

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

If you use ViewController in GameController, then you can add the import to GameController.m.

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

You probably have a circular dependency.

您可能有循环依赖。

The basic way to define a circular dependency is:

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

  • GameController.h imports ViewController.h
  • GameController.h导入ViewController.h
  • ViewController.h imports GameController.h
  • ViewController.h导入GameController.h

Which one will be seen first depends on the order of declaration in the translation, but obviously one will have to come first because in this case the headers disagree as to which must come first.

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

In a real codebase, you may #import "ViewController.h" in many source files. This creates very complex dependencies. These dependencies are largely unnecessary in ObjC -- you can use forward declarations most of the time in a header (and it will improve your build times).

在实际的代码库中,您可以在许多源文件中#import“ViewController.h”。这会创建非常复杂的依赖项。在ObjC中,这些依赖项基本上是不必要的 - 您可以在标题中大部分时间使用前向声明(并且它将改善您的构建时间)。

So I explained the simplest case, but what happens when 15 headers #import ViewController.h? Well, you would have to track down which header is introducing that circular dependency for that translation. If you don't manage dependencies well, then you may have to step through dozens (or hundreds) of files. Sometimes, it's easiest to just review the preprocessed output for that translation (e.g. the offending *.m file). If dependencies are not minimized, that output could be hundreds of thousands of lines (and your build times could be 20 or more times faster if it were managed correctly). So the complexity of locating circular dependencies quickly goes up in large codebases; the more you #import and #include in the headers. Using forward declarations in headers (where possible) solves this problem.

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

Example

So given your header in the OP, you could rewrite it as:

因此,考虑到OP中的标题,您可以将其重写为:

GameController.h

GameController.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

GameController.m

GameController.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
...

Then you can apply the same treatment to ViewController.h (which is importing GameController.h).

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

#2


0  

Are you certain that the class interface defined inside ViewController.h is also spelled as "ViewController"?

您确定ViewController.h中定义的类接口也拼写为“ViewController”吗?

I did a quick test by creating a ViewController.h class in my project, but renamed the interface to ViewControllers inside it and got the same error as you.

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