La mia richiesta è questa. Quando si usa #import e quando si usa @class?
Risposta semplice: tu #import
o #include
quando c'è una dipendenza fisica. In caso contrario, è possibile utilizzare le dichiarazioni previsionali ( @class MONClass
, struct MONStruct
,@protocol MONProtocol
).
Ecco alcuni esempi comuni di dipendenza fisica:
- Qualsiasi valore C o C ++ (un puntatore o un riferimento non è una dipendenza fisica). Se hai un
CGPoint
as ivar o una proprietà, il compilatore dovrà vedere la dichiarazione di CGPoint
.
- La tua superclasse.
- Un metodo che usi.
A volte se uso una dichiarazione @class, vedo un avviso comune del compilatore come il seguente: "avviso: il ricevitore 'FooController' è una classe diretta e la relativa @interfaccia potrebbe non esistere".
Il compilatore in realtà è molto indulgente in questo senso. Rilascerà suggerimenti (come quello sopra), ma puoi eliminare facilmente il tuo stack se li ignori e non lo fai #import
correttamente. Anche se dovrebbe (IMO), il compilatore non lo impone. In ARC, il compilatore è più rigoroso perché è responsabile del conteggio dei riferimenti. Quello che succede è che il compilatore ricade su un valore predefinito quando incontra un metodo sconosciuto che chiami. Si presume che ogni valore e parametro di ritorno siaid
. Quindi, dovresti sradicare ogni avviso dai tuoi codebase perché questo dovrebbe essere considerato dipendenza fisica. Ciò è analogo alla chiamata di una funzione C che non è dichiarata. Con C, si presume che i parametri siano int
.
Il motivo per cui si preferirebbero le dichiarazioni a termine è che è possibile ridurre i tempi di costruzione in base a fattori poiché esiste una dipendenza minima. Con le dichiarazioni forward, il compilatore vede che c'è un nome e può analizzare e compilare correttamente il programma senza vedere la dichiarazione di classe o tutte le sue dipendenze quando non c'è dipendenza fisica. Le build pulite richiedono meno tempo. Le build incrementali richiedono meno tempo. Certo, finirai per passare un po 'più di tempo assicurandoti che tutte le intestazioni di cui hai bisogno siano visibili ad ogni traduzione di conseguenza, ma ciò ripaga rapidamente in tempi di costruzione ridotti (supponendo che il tuo progetto non sia piccolo).
Se usi #import
o #include
invece, stai lanciando molto più lavoro sul compilatore di quanto sia necessario. Stai anche introducendo dipendenze complesse dell'intestazione. Puoi paragonarlo a un algoritmo a forza bruta. Quando tu#import
stai trascinando tonnellate di informazioni non necessarie, che richiedono molta memoria, I / O del disco e CPU per analizzare e compilare le fonti.
ObjC è abbastanza vicino all'ideale per un linguaggio basato su C per quanto riguarda la dipendenza perché i NSObject
tipi non sono mai valori -NSObject
tipi sono sempre puntatori contati come riferimento. In questo modo puoi cavartela con tempi di compilazione incredibilmente rapidi se strutturi le dipendenze del tuo programma in modo appropriato e in avanti, ove possibile, perché la dipendenza fisica è molto ridotta. È inoltre possibile dichiarare le proprietà nelle estensioni di classe per ridurre ulteriormente la dipendenza. Questo è un enorme vantaggio per i sistemi di grandi dimensioni: sapresti la differenza che fa se avessi mai sviluppato una base di codice C ++ di grandi dimensioni.
Pertanto, la mia raccomandazione è di usare i forward dove possibile, e quindi #import
dove c'è dipendenza fisica. Se vedi l'avvertimento o altro che implica dipendenza fisica, correggili tutti. La correzione è #import
nel file di implementazione.
Mentre costruisci librerie, classificherai probabilmente alcune interfacce come gruppo, nel qual caso dovresti #import
quella libreria in cui viene introdotta la dipendenza fisica (ad es #import <AppKit/AppKit.h>
.). Questo può introdurre dipendenza, ma i manutentori della libreria possono spesso gestire le dipendenze fisiche per te, se necessario - se introducono una funzionalità, possono minimizzare l'impatto che ha sulle tue build.