John da buenos consejos, pero aquí hay un poco más de antecedentes sobre los por qué, dónde y las excepciones.
Existen dos objetivos detrás de evitar la importación de encabezados en los encabezados: mejores tiempos de compilación incrementales y la evitación de dependencias circulares. Si importa A.h
en B.h
e importar B.h
en C.h
, entonces cada vez que cambie nada en A.h
, usted tiene que volver a compilar C.m
, incluso si C.m
no hace uso de ninguna de las cosas definidas en A.h
. Esto puede llevar a un abandono de la construcción realmente terrible e innecesario, especialmente si tiene encabezados que cambian con frecuencia (como es común en las primeras etapas de desarrollo).
El primer objetivo es loable, pero para proyectos pequeños, ¿a quién le importa? Tienes un Pro de cuatro núcleos y una compilación completa toma un par de minutos, ¿verdad? Pero aún debe preocuparse por el segundo problema: dependencias circulares. A.h
referencias clase B
y B.h
referencias clase A
. En realidad, esto puede suceder con bastante frecuencia y puede introducirse en un sistema de forma bastante inocente. Un objeto de colección podría hacer referencia al tipo de objetos que contiene, y los objetos podrían hacer referencia al tipo del objeto de colección. Todo lo que se necesita es una sola referencia debido a algún método que toma o devuelve ese tipo. Si tiene encabezados que importan otros encabezados, la probabilidad de que esto ocurra rápidamente se aproxima a la unidad. Terminas con importaciones recursivas, y los errores en tiempo de compilación pueden ser alucinantes. "I saber que typdef está definido!¡Está justo ahí! Se importa!" Sin embargo, no se ha analizado aún cuando se ha importado esta cabecera. Esto es lo que está causando su error anterior.
Por esta razón, incluso si no se preocupan mucho acerca de los tiempos de construcción (aunque usted debe), evitar la importación de cabeceras en las cabeceras ... excepto ....
Algunos encabezados que tiene importar. Su superclase, por supuesto. Los archivos que definen un @protocol
implementar o typedef
que utilice. Así que sí, tiene que incluir esos.
¿Y qué hay de los encabezados del sistema? Bueno, nunca van a c Ause mantequera, y obviamente no van a causar importaciones recursivas, entonces están bien. No recomiendo a las personas que usen el @class
declaraciones anticipadas para cosas en los encabezados del sistema. Crea trabajo adicional en el usuario de su encabezado sin ningún valor. Para una buena higiene del cabezal, recuerde encerrar los encabezados del sistema en < escuadras angulares > y sus encabezados entre comillas.
Así que no es una pregunta trivial, pero la regla simple es: evitar importar encabezados de usuario en otros encabezados de usuario cada vez que el compilador lo permita.
¿Qué pasa con 'typedef's y' protocols'? – Joost
¿No sabría usted de un tutorial, o una muestra de código que usa esto? – gargantuan