2009-08-03 18 views
11

Tengo el siguiente código:Objective-C import bucle

#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 

Se compila y funciona muy bien. Sin embargo, si se sustituyen las declaraciones de métodos con:

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

me sale el error de sintaxis inesperado "Error: se esperaba ')' antes 'ServerRequest'". La única razón por la que puedo pensar que esto podría ser un problema es que ServerRequestDelegate.h y ServerRequest.h # importan entre sí. Sin embargo, no entiendo por qué el código funciona con la solicitud #import line with (id). Tampoco entiendo por qué es un error de sintaxis.

¿Alguien puede dar una buena explicación?

+1

http://stackoverflow.com/questions/10019961/objective-c-class-directive-before-interface tiene un ejemplo explícito de un ciclo de importación y cómo evitarlo usando '@ class'. – bbum

Respuesta

24

Ya ha insinuado la explicación: un ciclo de importación.

La primera cosa que me gustaría hacer es quitar el #include y añadir la siguiente línea por encima de la definición @protocol:

@class ServerRequest; 

Ésta es una declaración de clase hacia adelante, y puede ayudar a romper el bucle de importación. Consulte this SO question para obtener más detalles. Apple también tiene una breve explicación en this guide.

Básicamente, #import 'ing un archivo hace que el compilador para llevar todo el texto de ese archivo en el archivo en cuestión, y aunque #import es 'más inteligentes' que #include, que no quiere decir que eres inmune a errores de importación . La declaración @class es una forma de decirle al compilador que existe una clase sin importar el encabezado. Es apropiado usarlo cuando solo se necesita saber sobre el nombre de la clase, pero no se preocupan por los métodos que proporciona. En general, desea utilizar @class en el archivo .h y #import en el archivo .m, donde en realidad está interactuando con la clase.

+0

Sí, mudarse a @class declares en el encabezado es mejor en cualquier número de niveles, pero a menos que el problema sean las dependencias circulares sin una declaración adelantada apropiada, es posible que haya un error latente en el encabezado. –

+1

Eso es cierto, pero el hecho de que funcione con el encabezado incluido si usa 'id' como tipo, pero no cuando tipea estáticamente como' ServerRequest * 'es un indicador de que el encabezado probablemente está bien, y el compilador solo tiene un problema cuando comienza a tratar de encontrar información sobre la clase 'ServerRequest'. –

0

#import "bucles" no son un problema. #import es lo mismo que #include, excepto que rastrea los archivos y se asegura de que el preprocesador los lea solo la primera vez.

Normalmente, cuando recibe un error como ese, se debe a un problema en el archivo incluido. Entonces, el error probablemente esté en ServerResponseRecord.h, pensó que probablemente se disparó al usar realmente el objeto declarado por él. Sin ver los encabezados completos, no es posible decir exactamente lo que está sucediendo.

+0

Si hubiera un problema en ServerResponseRecord, ¿por qué mi código se compilaría y ejecutaría correctamente si cambio el tipo a id? – tba

+0

Porque el preprocesador es un truco y algunas expansiones solo se pueden desencadenar en ciertos casos pero no en otros. Si está mirando el archivo de forma aislada, parece correcto, suponiendo que ServerRequest y ServerResponseRecord tienen definiciones válidas. Al declararlos usando @class, lo has probado, lo que significa que hay un error latente en uno de tus otros encabezados que solo se dispara en algunos casos. –