2009-08-03 6 views
11

У меня есть следующий код:Objective-C#import петля

#import <Foundation/Foundation.h> 
#import "ServerRequest.h" // works even though this line is included 
#import "ServerResponseRecord.h" 

@protocol ServerRequestDelegate<NSObject> 

-(void)request:(id)request gotResponseRecord:(ServerResponseRecord*)response; 
-(void)request:(id)request gotError:(NSError*)error; 

@end 

Это компилирует и работает нормально. Однако, если я заменю заявление метод с:

-(void)request:(ServerRequest*)request gotResponseRecord:(ServerResponseRecord*)response; 
-(void)request:(ServerRequest*)request gotError:(NSError*)error; 

я получаю неожиданную синтаксическую ошибку «ошибку: ожидается„)“до„ServerRequest“». Единственная причина, по которой я могу думать, что это может быть проблемой, заключается в том, что ServerRequestDelegate.h и ServerRequest.h #import друг друга. Однако я не понимаю, почему код работает с линией #import с запросом (id). Я также не понимаю, почему это синтаксическая ошибка.

Может ли кто-нибудь дать хорошее объяснение?

+1

http://stackoverflow.com/questions/10019961/objective-c-class-directive-before-interface имеет явный пример цикла импорта и как его избежать, используя '@ class'. – bbum

ответ

24

Вы уже намекнули на объяснение: цикл #import.

Первое, что я хотел бы сделать, это удалить #include и добавьте следующую строку выше @protocol определения:

@class ServerRequest; 

Это декларация вперед класс, и может помочь разорвать цикл импорта. Для получения более подробной информации посетите this SO question. У Apple также есть краткое объяснение в this guide.

В основном, #import «ИНГ файл вызывает компилятор, чтобы привести весь текст этого файла в файл в вопросе, и хотя #import является„умнее“, чем #include, это не означает, что вы застрахованы от ошибок импорта , Объявление @class - это способ сообщить компилятору, что класс существует без импорта заголовка. Уместно использовать, когда вам нужно знать только имя класса, но не заботятся о методах, которые он предоставляет. Как правило, вы хотите использовать @class в файле .h и #import в файле .m, где вы фактически взаимодействуете с классом.

+0

Да, переход на @class в заголовке лучше в любом количестве уровней, но если проблема не была круговой зависимостью без соответствующего объявления прямого объявления, в заголовке может быть скрытая ошибка. –

+1

Это правда, но тот факт, что он работает с заголовком, включен, если он использует 'id' в качестве типа, но не тогда, когда статическая типизация как« ServerRequest * »является индикатором того, что заголовок, вероятно, в порядке, и у компилятора только есть когда он начинает пытаться узнать информацию о классе ServerRequest. –

0

#import "петли" не являются проблемой. #import - это то же самое, что и #include, за исключением того, что он отслеживает файлы и гарантирует, что препроцессор читает их только в первый раз.

Обычно, когда вы получаете такую ​​ошибку, это связано с проблемой во включенном файле. Таким образом, ошибка, вероятно, в ServerResponseRecord.h, считается, что она, вероятно, сработала, фактически используя объявленный ею объект. Не видя полных заголовков, невозможно точно сказать, что происходит.

+0

Если в ServerResponseRecord возникла проблема, почему мой код будет компилироваться и работать нормально, если я изменю тип на id? – tba

+0

Поскольку препроцессор является сложным, и некоторые расширения могут запускаться только в определенных случаях, но не в других. Если вы ищете изолированный файл, он кажется хорошим, если ServerRequest и ServerResponseRecord имеют действительные определения. Переадресацией, объявляющей их с помощью @class, вы доказали это, а это означает, что в одном из ваших других заголовков есть скрытая ошибка, которая в некоторых случаях срабатывает только. –