2009-08-03 15 views
11

Ho il seguente codice:Objective-C# import ciclo

#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 

Si compila e funziona bene. Tuttavia, se sostituisco le dichiarazioni di metodo con:

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

ottengo l'inaspettato errore di sintassi "Errore: Previsto ')' prima 'ServerRequest'". L'unica ragione per cui posso pensare che questo potrebbe essere un problema è che ServerRequestDelegate.h e ServerRequest.h # si importano a vicenda. Tuttavia, non capisco perché il codice funzioni con la riga #import con la richiesta (id). Inoltre, non capisco perché si tratta di un errore di sintassi.

Qualcuno può fornire una buona spiegazione?

+1

http://stackoverflow.com/questions/10019961/objective-c-class-directive-before-interface ha un esempio esplicito di un ciclo di importazione e come evitarlo usando '@ class'. – bbum

risposta

24

Hai già accennato alla spiegazione: un ciclo #import.

La prima cosa che farei è togliere il #include e aggiungere la seguente riga sopra la definizione @protocol:

@class ServerRequest; 

Si tratta di una dichiarazione di classe in avanti, e può contribuire a spezzare il ciclo di importazione. Controlla this SO question per maggiori dettagli. Apple ha anche una breve spiegazione in this guide.

In sostanza, #import 'ing un file fa sì che il compilatore di portare l'intero testo di quel file nel file in questione, e anche se #import è 'più intelligente' rispetto #include, ciò non significa che sei immune da errori di importazione . La dichiarazione @class è un modo per dire al compilatore che esiste una classe senza importare l'intestazione. È opportuno utilizzarlo quando è necessario conoscere solo il nome della classe, ma non preoccuparsi dei metodi che fornisce. In genere, si desidera utilizzare @class nel file .h e #import nel file .m, in cui si sta effettivamente interagendo con la classe.

+0

Sì, lo spostamento su @class dichiara nell'header è migliore a qualsiasi numero di livelli, ma a meno che il problema non fosse una dipendenza circolare senza una dichiarazione forward appropriata, potrebbe comunque esserci un bug latente nell'intestazione. –

+1

Questo è vero, ma il fatto che funzioni con l'intestazione include se usa 'id' come tipo, ma non quando la tipizzazione statica come' ServerRequest * 'è un indicatore che l'intestazione è probabilmente ok, e il compilatore ha solo un problema quando inizia a cercare di carpire informazioni sulla classe 'ServerRequest'. –

0

#import "loop" non sono un problema. #importare è lo stesso di #include tranne per il fatto che tiene traccia dei file e si assicura che il preprocessore li legga solo per la prima volta.

Di solito quando si verifica un errore del genere è dovuto a un problema nel file incluso. Quindi l'errore è probabilmente in ServerResponseRecord.h, pensavo che probabilmente è stato fatto intervenire usando effettivamente l'oggetto da esso dichiarato. Senza vedere le intestazioni complete non è possibile dire esattamente cosa sta succedendo.

+0

Se ci fosse un problema in ServerResponseRecord, perché il mio codice sarebbe compilato ed eseguito bene se cambio il tipo in id? – tba

+0

Perché il preprocessore è un problema e alcune espansioni possono essere attivate solo in alcuni casi ma non in altri. Se si sta osservando il file da solo, sembra opportuno presumere che ServerRequest e ServerResponseRecord abbiano definizioni valide. Inoltrandoli dichiarandoli usando @class hai dimostrato che, il che significa che c'è un errore latente in uno dei tuoi altri header che si innesca solo in alcuni casi. –