Mi consulta es esta. ¿Cuándo se usa #import y cuándo se usa @class?
Respuesta simple: usted #import
o #include
cuando hay una dependencia física. De lo contrario, se utiliza declaraciones adelantadas ( @class MONClass
, struct MONStruct
, @protocol MONProtocol
).
Aquí hay algunos ejemplos comunes de dependencia física:
- Cualquier valor de C o C ++ (un puntero o referencia no es una dependencia física). Si tiene un
CGPoint
como ivar o propiedad, el compilador deberá ver la declaración de CGPoint
.
- Tu superclase.
- Un método que usas.
A veces, si uso una declaración @class, veo una advertencia común del compilador como la siguiente: "advertencia: el receptor 'FooController' es una clase de reenvío y la interfaz @ correspondiente puede no existir".
El compilador es realmente muy indulgente a este respecto. Caerá pistas (como la anterior), pero puede tirar basura a la pila fácilmente si las ignora y no lo hace #import
correctamente. Aunque debería (IMO), el compilador no aplica esto. En ARC, el compilador es más estricto porque es responsable del recuento de referencias. Lo que sucede es que el compilador recurre a un valor predeterminado cuando encuentra un método desconocido al que llama. Se supone que cada valor de retorno y parámetro es id
. Por lo tanto, debe erradicar todas las advertencias de sus bases de código porque esto debe considerarse dependencia física. Esto es análogo a llamar a una función C que no se declara. Con C, se supone que los parámetros son int
.
La razón por la que preferiría las declaraciones adelantadas es que puede reducir sus tiempos de compilación por factores porque hay una dependencia mínima. Con las declaraciones directas, el compilador ve que hay un nombre y puede analizar y compilar correctamente el programa sin ver la declaración de clase o todas sus dependencias cuando no hay dependencia física. Las construcciones limpias toman menos tiempo. Las construcciones incrementales toman menos tiempo. Claro, terminará pasando un poco más de tiempo asegurándose de que todos los encabezados que necesita sean visibles para cada traducción como consecuencia, pero esto se amortiza en tiempos de construcción reducidos rápidamente (suponiendo que su proyecto no sea pequeño).
Si usa #import
o #include
, en cambio, está lanzando mucho más trabajo en el compilador de lo necesario. También está introduciendo dependencias complejas de encabezado. Puede comparar esto con un algoritmo de fuerza bruta. Cuando usted #import
, está arrastrando toneladas de información innecesaria, que requiere mucha memoria, E / S de disco y CPU para analizar y compilar las fuentes.
ObjC es bastante ideal para un lenguaje basado en C con respecto a la dependencia porque los NSObject
tipos nunca son valores, los NSObject
tipos son siempre punteros contados por referencia. Por lo tanto, puede escapar con tiempos de compilación increíblemente rápidos si estructura las dependencias de su programa de manera adecuada y reenvía donde sea posible porque se requiere muy poca dependencia física. También puede declarar propiedades en las extensiones de clase para minimizar aún más la dependencia. Esa es una gran ventaja para sistemas grandes: sabría la diferencia que hace si alguna vez ha desarrollado una gran base de código C ++.
Por lo tanto, mi recomendación es usar reenvíos siempre que sea posible, y luego a #import
donde haya dependencia física. Si ve la advertencia u otra que implique dependencia física, corríjalas todas. La solución está #import
en su archivo de implementación.
A medida que construye bibliotecas, es probable que clasifique algunas interfaces como un grupo, en cuyo caso elegiría #import
la biblioteca donde se introduce la dependencia física (por ejemplo #import <AppKit/AppKit.h>
). Esto puede introducir dependencia, pero los mantenedores de la biblioteca a menudo pueden manejar las dependencias físicas por usted según sea necesario; si presentan una característica, pueden minimizar el impacto que tiene en sus compilaciones.