Qual è la differenza tra #import e #include in Objective-C?


Risposte:


340

La direttiva #import è stata aggiunta a Objective-C come versione migliorata di #include. Il miglioramento, comunque, è ancora oggetto di dibattito. #import assicura che un file venga incluso solo una volta in modo da non avere mai problemi con le inclusioni ricorsive. Tuttavia, la maggior parte dei file di intestazione decenti si proteggono comunque da questo, quindi non è davvero un grande vantaggio.

Fondamentalmente, sta a te decidere quale vuoi usare. Tendo a #importare le intestazioni per oggetti Objective-C (come definizioni di classe e simili) e #includere elementi C standard di cui ho bisogno. Ad esempio, uno dei miei file di origine potrebbe essere simile al seguente:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>

65
Anche se i file di intestazione contengono protezioni di inclusione, durante la compilazione si verifica comunque un calo delle prestazioni se si utilizza #include: il compilatore deve aprire ciascun file di intestazione per notare le protezioni di inclusione.
Matt Dillard,

4
un header guard è una direttiva preprocessore che garantisce che un header sia incluso solo una volta in un file sorgente.
Jason Coco,

8
Penso che #import sia in realtà un'aggiunta di GCC, non di Objective-C. Puoi usarlo in linguaggi non ObjC purché compili con GCC (o Clang)
Dave DeLong,

34
@dave - #import è un'aggiunta di Objective-C al preprocessore. GCC lo supporta anche nei file sorgente C e C ++, sebbene suggeriscano ufficialmente di non usarlo in C o C ++ a favore delle protezioni per le intestazioni portatili e tradizionali. Tutti i preprocessori Objective-C devono tuttavia includere #import.
Jason Coco,

13
Una guardia di intestazione è dove aggiungi in alto: #ifndef myheader #define myheader ... seguito dal codice di intestazione ...#endif
Tim

359

Sembra esserci molta confusione riguardo al preprocessore.

Cosa fa il compilatore quando vede #includeche sostituisce quella linea con il contenuto dei file inclusi, senza fare domande.

Quindi se hai un file a.hcon questo contenuto:

typedef int my_number;

e un file b.ccon questo contenuto:

#include "a.h"
#include "a.h"

il file b.cverrà tradotto dal preprocessore prima della compilazione in

typedef int my_number;
typedef int my_number;

che comporterà un errore del compilatore, poiché il tipo my_numberviene definito due volte. Anche se la definizione è la stessa, ciò non è consentito dal linguaggio C.

Poiché un'intestazione viene spesso utilizzata in più di un posto , in genere le protezioni vengono utilizzate in C. Questo è simile al seguente:

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif

Il file b.cavrebbe comunque l'intero contenuto dell'intestazione due volte dopo essere stato preelaborato. Ma la seconda istanza verrebbe ignorata poiché la macro _a_h_included_sarebbe già stata definita.

Funziona davvero bene, ma ha due inconvenienti. Prima di tutto devono essere scritte le protezioni di inclusione e il nome della macro deve essere diverso in ogni intestazione. In secondo luogo, il compilatore deve ancora cercare il file di intestazione e leggerlo tutte le volte che è incluso.

Objective-C ha l' #importistruzione preprocessore (può anche essere usato per codice C e C ++ con alcuni compilatori e opzioni). Questo fa quasi lo stesso #include, ma nota anche internamente quale file è già stato incluso. La #importriga viene sostituita solo dal contenuto del file indicato per la prima volta che viene rilevata. Ogni volta dopo viene semplicemente ignorato.


5
Questa è la risposta migliore di quella accettata. @Guill, dovresti cambiare la risposta accettata.
Nguyen Minh Binh,

6
Dopo aver modificato da 4 #includes a #imports su un file di intestazione del modello di linea 7000, si riscontra un notevole miglioramento delle prestazioni nella compilazione e nella reattività di XCode intellisense. (Non credo di immaginarlo)
bobobobo

63

Sono d'accordo con Jason.

Sono stato sorpreso a fare questo:

#import <sys/time.h>  // to use gettimeofday() function
#import <time.h>      // to use time() function

Per GNU gcc, continuava a lamentarsi del fatto che la funzione time () non era definita.

Quindi ho cambiato #import in #include e tutto è andato bene.

Motivo:

#Import <sys / time.h>:
    <sys / time.h> include solo una parte di <time.h> usando #defines

#Import <time.h>:
    No go. Anche se solo una parte di <time.h> era già inclusa, per quanto
    riguarda #import, quel file è ora già completamente incluso.

Linea di fondo:

Le intestazioni C / C ++ includono tradizionalmente parti di altri file di inclusione.
Quindi, per le intestazioni C / C ++, usa #include.
Per le intestazioni objc / objc ++, usa #import.


2
Sembra che Clang non abbia questo problema non definito.
ooops il

23

#includefunziona proprio come il C #include.

#importtiene traccia di quali intestazioni sono già state incluse e viene ignorato se un'intestazione viene importata più di una volta in un'unità di compilazione. Ciò rende superfluo l'uso delle protezioni delle testate.

La linea di fondo è solo usare #importin Objective-C e non preoccuparti se le tue intestazioni finiscono per importare qualcosa più di una volta.


2
fingendo per un minuto di non avere familiarità con C #include (principalmente perché non lo sono), qual è la differenza principale tra #include e #import? Inoltre, puoi dirmi cos'è una guardia di intestazione?
Ryan Guill,

@Ryan: guarda la risposta di Sven.
Adrian Petrescu,

13

So che questa discussione è vecchia ... ma nei "tempi moderni" .. c'è una "strategia" inclusiva di gran lunga superiore attraverso i @importmoduli di clang - che è spesso trascurata ..

I moduli migliorano l'accesso all'API delle librerie software sostituendo il modello testuale di inclusione del preprocessore con un modello semantico più robusto, più efficiente. Dal punto di vista dell'utente, il codice appare solo leggermente diverso, perché si utilizza una dichiarazione di importazione piuttosto che una direttiva preprocessore #include:

@import Darwin; // Like including all of /usr/include. @see /usr/include/module.map

o

@import Foundation;  //  Like #import <Foundation/Foundation.h>
@import ObjectiveC;  //  Like #import <objc/runtime.h>

Tuttavia, l'importazione di questo modulo si comporta in modo abbastanza diverso dalla corrispondente #include: quando il compilatore vede l'importazione del modulo sopra, carica una rappresentazione binaria del modulo e rende la sua API disponibile direttamente all'applicazione. Le definizioni del preprocessore che precedono la dichiarazione di importazione non hanno alcun impatto sull'API fornita ... poiché il modulo stesso è stato compilato come modulo separato e autonomo. Inoltre, ogni flag linker richiesto per utilizzare il modulo verrà automaticamente fornito quando il modulo viene importato. Questo modello di importazione semantica risolve molti dei problemi del modello di inclusione del preprocessore.

Per abilitare i moduli, passare il flag della riga di comando -fmodulesaka CLANG_ENABLE_MODULESin Xcode- al momento della compilazione. Come accennato in precedenza .. questa strategia ovvia a TUTTI e TUTTI LDFLAGS. Come in, puoi RIMUOVERE qualsiasi impostazione di "OTHER_LDFLAGS", nonché qualsiasi fase di "Collegamento".

inserisci qui la descrizione dell'immagine

Trovo i tempi di compilazione / avvio per "sentire" molto più scattanti (o forse, c'è solo un po 'di ritardo durante il "collegamento"?) .. e inoltre, offre una grande opportunità per eliminare il file Project-Prefix.pch ora estraneo, e corrispondenti impostazioni di generazione, GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADER, e GCC_PREFIX_HEADER, etc.

Inoltre, sebbene non ben documentato ... È possibile creare messaggi di posta module.mapelettronica per i propri framework e includerli nello stesso modo conveniente. Puoi dare un'occhiata al mio repository github di ObjC-Clang-Modules per alcuni esempi di come realizzare tali miracoli.


4

Se hai familiarità con C ++ e macro, allora

#import "Class.h" 

è simile a

{
#pragma once

#include "class.h"
}

ciò significa che la tua classe verrà caricata una sola volta quando l'app verrà eseguita.


È un uso supportato di #pragma una volta? Ho sempre pensato che il pragma bisogno di essere dentro il includ ndr file da lavoro.
uliwitness,

@uliwitness Hai ragione. #pragma onceviene inserito nel file incluso, non nel file che esegue l'inclusione. -1 per quello.
Herzbube,

1

In caso avessi avuto una variabile globale in uno dei miei .hfile che stava causando il problema, e l'ho risolto aggiungendolo externdavanti.


0

Se #includi un file due volte nei file .h del compilatore genererà un errore. Ma se #importi un file più di una volta il compilatore lo ignorerà.


8
#includelo stesso file due volte non provoca un errore.
kennytm,

1
A complemento del commento di @ KennyTM, # l'inclusione dello stesso file due volte nella stessa intestazione non provoca un errore di compilazione SE ci sono i soliti guardiani dell'intestazione (#ifndef FILE_NAME_H #define FILE_NAME_H #end). Questa è una pratica prevista. Utilizzando #import non sono necessarie le protezioni per le intestazioni.
jbat100,

@ jbat100: #includeè semplicemente un meccanismo di copia e incolla. Vi è un uso deliberato di #includepiù di una volta senza includere protezioni, ad esempio la "macro X".
kennytm,

L'inclusione di un file due volte può causare errori a seconda di ciò che si include. Ho visto il codice C usato #includeper implementare una sorta di template. Hanno fatto un #define, incluso un header, de il #undefredid #define, incluso lo stesso header una seconda volta. Ciò ha comportato la parametrizzazione, la validità e l'inclusione del codice di due volte, poiché il valore della definizione era diverso. Quindi ci sono vantaggi nell'uso #include, ma se stai usando un linguaggio moderno come C ++ o ObjC, generalmente non hai bisogno di questo.
uliwitness

0

#includeha usato per ottenere "cose" da un altro file a quello in cui #includeè usato. Esempio:

nel file: main.cpp

#include "otherfile.h"

// some stuff here using otherfile.h objects,
// functions or classes declared inside

La protezione della testata viene utilizzata nella parte superiore di ciascun file di intestazione (* .h) per evitare di includere lo stesso file più di una volta (in tal caso si verificheranno errori di compilazione).

nel file: otherfile.h

#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif

anche se inserisci #include"otherfile.h" n nel tuo codice, questo al suo interno non verrà rideclarato.


0
#include + guard == #import

#include guardWiki : la protezione macro, la protezione dell'intestazione o la protezione dei file impediscono di includere due volte un'intestazionepreprocessorche può rallentare un tempo di compilazione

Il prossimo passo è

.pch[Informazioni] =>@import [Informazioni]

[#import in .ho .m]

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.