Цель C — ошибка: «Ожидается тип»

Я получаю очень странную ошибку в чем-то, что я считал простым.

#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

person user2577959    schedule 12.07.2013    source источник
comment
Как определяется ViewController?   -  person Wain    schedule 13.07.2013
comment
Это может помочь вам, аналогичный вопрос: stackoverflow.com/a/9607607/1422070   -  person edwardmp    schedule 13.07.2013
comment
Возможно, внутри файла .h вы неправильно написали имя класса.   -  person Ramy Al Zuhouri    schedule 13.07.2013
comment
кинуть @class ViewController; над @interface   -  person Grady Player    schedule 13.07.2013
comment
@GradyPlayer Почему он уже включен? #import "ViewController.h" Нет необходимости в предварительном объявлении.   -  person David Rönnqvist    schedule 13.07.2013
comment
@DavidRönnqvist, что, безусловно, не является требованием, чтобы файл с именем ViewController.h содержал интерфейс для класса ViewController.   -  person Grady Player    schedule 13.07.2013


Ответы (2)


Используйте предварительное объявление: @class ViewController; вместо #import "ViewController.h". Импорт обычно не нужен в другом заголовке в Objective-C.

Если вы используете ViewController в GameController, то вы можете добавить импорт в GameController.m.

Возможно, у вас круговая зависимость.

Основной способ определения циклической зависимости:

  • GameController.h импортирует ViewController.h
  • ViewController.h импортирует GameController.h

Какой из них будет отображаться первым, зависит от порядка объявления в переводе, но, очевидно, один из них должен стоять первым, потому что в этом случае заголовки расходятся во мнениях относительно того, какой из них должен стоять первым.

В реальной кодовой базе вы можете #import "ViewController.h" использовать многие исходные файлы. Это создает очень сложные зависимости. Эти зависимости в значительной степени не нужны в ObjC — вы можете использовать предварительные объявления большую часть времени в заголовке (и это сократит время сборки).

Итак, я объяснил простейший случай, но что происходит, когда 15 заголовков #import ViewController.h? Что ж, вам нужно будет отследить, какой заголовок вводит эту циклическую зависимость для этого перевода. Если вы плохо управляете зависимостями, вам, возможно, придется просмотреть десятки (или сотни) файлов. Иногда проще просто просмотреть предварительно обработанный вывод для этого перевода (например, оскорбительный файл *.m). Если зависимости не сведены к минимуму, этот вывод может состоять из сотен тысяч строк (и время сборки может быть в 20 или более раз быстрее, если им правильно управлять). Таким образом, сложность обнаружения циклических зависимостей быстро возрастает в больших кодовых базах; тем больше у вас #import и #include в заголовках. Использование предварительных объявлений в заголовках (где это возможно) решает эту проблему.

Пример

Итак, учитывая ваш заголовок в OP, вы можете переписать его как:

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

#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).

person justin    schedule 12.07.2013
comment
Я включил предварительную декларацию и импортировал заголовок в файл '.m'. Я все еще получаю ту же ошибку. Не могли бы вы немного подробнее объяснить проблему «круговой зависимости»? - person user2577959; 13.07.2013
comment
Мой проект имеет эту круговую зависимость. Как мне это исправить? - person user2577959; 13.07.2013
comment
Поэтому я изменил весь свой импорт на предварительные объявления классов, и ошибка исчезла. Что именно происходит, когда я это делаю? Рекомендуется, чтобы именно так я обрабатывал импорт всех классов? - person user2577959; 13.07.2013
comment
@user2577959 переадресация в заголовках намного лучше, чем импорт. в некоторых случаях вам понадобится импорт (например, класс, из которого вы производитесь, должен быть видимым). предварительное объявление @class ViewController просто сообщает компилятору, что существует тип objc с именем ViewController, и как только он узнает, ему не нужно видеть объявление класса. если вы хотите создать использование интерфейса ViewController в переводе, вы импортируете. - person justin; 13.07.2013
comment
@user2577959 user2577959, когда импортировать, ответил здесь, на SO… (смотрит) пожалуйста - person justin; 13.07.2013
comment
@ user2577959: Вот основная проблема: когда вы пишете #import something, компилятор по существу берет содержимое этого something и копирует и вставляет его в компилируемый файл. Но когда два файла оба #import друг друга, это невозможно, потому что один должен идти раньше другого, поэтому один из них заканчивается разочарованием, и вы получаете ошибку. - person Chuck; 13.07.2013

Вы уверены, что интерфейс класса, определенный внутри ViewController.h, также пишется как "ViewController"?

Я сделал быстрый тест, создав класс ViewController.h в своем проекте, но переименовал интерфейс в ViewControllers внутри него и получил ту же ошибку, что и вы.

person Sid    schedule 12.07.2013
comment
Не могли бы вы опубликовать объявления для ViewController? - person Sid; 13.07.2013