Minha pergunta é essa. Quando alguém usa #import e quando usa @class?
Resposta simples: você #import
ou #include
quando há uma dependência física. Caso contrário, você pode usar declarações para a frente ( @class MONClass
, struct MONStruct
, @protocol MONProtocol
).
Aqui estão alguns exemplos comuns de dependência física:
- Qualquer valor C ou C ++ (um ponteiro ou referência não é uma dependência física). Se você possui um
CGPoint
ivar ou propriedade, o compilador precisará ver a declaração de CGPoint
.
- Sua superclasse.
- Um método que você usa.
Às vezes, se eu usar uma declaração @class, vejo um aviso comum do compilador, como o seguinte: "warning: receiver 'FooController' é uma classe forward e @interface correspondente pode não existir".
O compilador é realmente muito indulgente a esse respeito. Ele soltará sugestões (como a acima), mas você pode lixeira sua pilha facilmente se ignorá-las e não fizer isso #import
corretamente. Embora deva (IMO), o compilador não impõe isso. No ARC, o compilador é mais rigoroso porque é responsável pela contagem de referências. O que acontece é que o compilador volta ao padrão quando encontra um método desconhecido que você chama. Todo valor e parâmetro de retorno é assumido como sendo id
. Portanto, você deve erradicar todos os avisos de suas bases de código, pois isso deve ser considerado dependência física. Isso é análogo a chamar uma função C que não é declarada. Com C, os parâmetros são assumidos como sendo int
.
O motivo de você favorecer as declarações de encaminhamento é que você pode reduzir o tempo de construção por fatores, porque há uma dependência mínima. Com as declarações de encaminhamento, o compilador vê que há um nome e pode analisar e compilar corretamente o programa sem ver a declaração de classe ou todas as suas dependências quando não houver dependência física. Construções limpas levam menos tempo. Construções incrementais levam menos tempo. Claro, você acabará gastando um pouco mais de tempo, garantindo que todos os cabeçalhos necessários sejam visíveis para todas as traduções como conseqüência, mas isso compensa em tempos de compilação reduzidos rapidamente (assumindo que seu projeto não seja pequeno).
Se você usar #import
ou #include
, em vez disso, estará lançando muito mais trabalho no compilador do que o necessário. Você também está introduzindo dependências complexas de cabeçalho. Você pode comparar isso com um algoritmo de força bruta. Quando você #import
está arrastando toneladas de informações desnecessárias, o que requer muita memória, E / S de disco e CPU para analisar e compilar as fontes.
O ObjC é bem próximo do ideal para uma linguagem baseada em C no que diz respeito à dependência, porque os NSObject
tipos nunca são valores - os NSObject
tipos sempre são indicadores contados como referência. Assim, você poderá obter tempos de compilação incrivelmente rápidos se estruturar adequadamente as dependências do programa e avançar sempre que possível, porque é necessária uma dependência física muito pequena. Você também pode declarar propriedades nas extensões de classe para minimizar ainda mais a dependência. Esse é um grande bônus para sistemas grandes - você saberia a diferença que faz se já desenvolveu uma grande base de código C ++.
Portanto, minha recomendação é usar os encaminhadores sempre que possível e depois para #import
onde houver dependência física. Se você vir o aviso ou outro que implica dependência física - corrija-os todos. A correção está #import
no seu arquivo de implementação.
Ao criar bibliotecas, você provavelmente classificará algumas interfaces como um grupo; nesse caso, você classificaria #import
a biblioteca em que a dependência física é introduzida (por exemplo #import <AppKit/AppKit.h>
). Isso pode introduzir dependência, mas os mantenedores da biblioteca geralmente podem lidar com as dependências físicas conforme necessário - se eles introduzirem um recurso, poderão minimizar o impacto que ele tem nas suas construções.