2009-08-03 7 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#が互いに衝突することです。しかし、(id)要求で#import行でコードが動作する理由はわかりません。私はまた、それが構文エラーである理由を理解していません。

誰かが良い説明をしてくれますか?

+1

http://stackoverflow.com/questions/10019961/objective-c-class-directive-before-interfaceには、インポートループの明示的な例と、 '@ class'を使用して回避する方法があります。 – bbum

答えて

24

あなたはすでに説明をヒントしました:#インポートサイクル。

私がしたいまず最初は#includeを削除し、@protocol定義の上に次の行を追加します。

@class ServerRequest; 

これは前方クラス宣言で、輸入ループを破ることができます。詳細についてはthis SO questionをご覧ください。 Appleはまた、this guideの簡単な説明をしています。

基本的には、#importは「ファイルをINGのは、問題のファイルに、そのファイルのテキスト全体を持参するようにコンパイラが発生し、#import#includeより 『賢く』ですが、それはあなたがインポートエラーから免疫しているという意味ではありません。 @class宣言は、ヘッダーをインポートせずにクラスが存在することをコンパイラーに通知する方法です。クラス名について知る必要があるだけで、それが提供するメソッドについては気にしないときに使用するのが適切です。一般に、.hファイルには@classを使用し、実際にはクラスと対話している.mファイルには#importを使用します。

+0

はい、ヘッダ内の@class宣言への移動は、任意の数のレベルで優れていますが、問題が適切な順方向宣言がない循環依存でない限り、ヘッダに潜在的なバグが残っている可能性があります。 –

+1

これは当てはまりますが、型として 'id'を使用するとヘッダーが含まれていて、' ServerRequest * 'として静的に型付けされている場合はヘッダーが正しく機能していることを示すインジケーターです。 'ServerRequest'クラスに関する情報を取得しようとすると、問題が発生します。 –

0

#import "loops"は問題ありません。 #importは#includeと同じですが、ファイルを追跡し、プリプロセッサが最初にそれらを読み込むことを確認します。

通常、このようなエラーが発生した場合は、インクルードファイルの問題が原因です。だからおそらくServerResponseRecord.hにエラーがあり、おそらく実際にそれによって宣言されたオブジェクトを使用してトリップされていると考えられます。完全な見出しを見ることなく、何が起こっているのかを正確に言うことはできません。

+0

ServerResponseRecordに問題があった場合、型をidに変更すると、私のコードはコンパイルされて正常に動作します。 – tba

+0

プリプロセッサはトリッキーなものであり、一部の展開は特定の場合にのみトリガされることがありますが、他のものはトリガされない可能性があります。あなたがファイルを単独で見ているなら、ServerRequestとServerResponseRecordが有効な定義を持っていると仮定すると良いでしょう。 @classを使用してそれらを前方に宣言すれば、それは、場合によってはトリガするだけの他のヘッダの潜在的なエラーがあることを証明しています。 –