web-dev-qa-db-fra.com

Quelle est la différence entre #import et #include dans Objective-C?

Quelles sont les différences entre #import et #include dans Objective-C et existe-t-il des moments où vous devriez utiliser l'un sur l'autre? Est-ce que l'un est obsolète?

Je lisais le tutoriel suivant: http://www.otierney.net/objective-c.html#preamble et son paragraphe relatif à #import et #include semble se contredire ou du moins n’est pas clair.

379
Ryan Guill

La directive #import a été ajoutée à Objective-C en tant que version améliorée de #include. Que ce soit amélioré ou non, cependant, reste un sujet de débat. #import garantit qu'un fichier n'est inclus qu'une seule fois, de sorte que vous ne rencontrez jamais de problème d'inclusions récursives. Cependant, la plupart des fichiers d'en-tête corrects se protègent de toute façon, ce n'est donc pas vraiment un avantage.

C'est à vous de décider lequel vous voulez utiliser. J'ai tendance à # importer les en-têtes pour les éléments Objective-C (comme les définitions de classe, etc.) et # inclure les éléments C standards dont j'ai besoin. Par exemple, un de mes fichiers source pourrait ressembler à ceci:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>
337
Jason Coco

Il semble y avoir beaucoup de confusion concernant le pré-processeur.

Que fait le compilateur quand il voit un #include qu'il remplace cette ligne par le contenu des fichiers inclus, sans poser de questions?.

Donc, si vous avez un fichier a.h avec ce contenu:

typedef int my_number;

et un fichier b.c avec ce contenu:

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

le fichier b.c sera traduit par le préprocesseur avant la compilation en

typedef int my_number;
typedef int my_number;

ce qui entraînera une erreur de compilation, car le type my_number est défini deux fois. Même si la définition est la même, cela n’est pas autorisé par le langage C.

Puisqu'un en-tête est souvent utilisé à plus d'un endroit inclure les gardes sont habituellement utilisés en C. Cela ressemble à ceci:

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif

Le fichier b.c contient toujours le contenu entier de l'en-tête deux fois après le prétraitement. Mais la seconde instance serait ignorée car la macro _a_h_included_ aurait déjà été définie.

Cela fonctionne vraiment bien, mais a deux inconvénients. Tout d'abord, les gardes d'inclusion doivent être écrits et le nom de la macro doit être différent dans chaque en-tête. Et deuxièmement, le compilateur doit encore rechercher le fichier d’en-tête et le lire aussi souvent qu’il est inclus.

Objective-C possède l'instruction de préprocesseur #import (elle peut également être utilisée pour le code C et C++ avec certains compilateurs et options). Cela fait presque la même chose que #include, mais il note également en interne quel fichier a déjà été inclus. La ligne #import n'est remplacée que par le contenu du fichier nommé pour la première fois qu'il est rencontré. Chaque fois après cela, il est simplement ignoré.

347
Sven

Je suis d'accord avec Jason.

Je me suis fait prendre à faire ceci:

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

Pour GNU gcc, il s'est plaint de ne pas définir la fonction time ().

Alors j'ai changé #import en #include et tout s'est bien passé.

Raison:

Vous #importez <sys/time.h>:
<Sys/time.h> inclut seulement un partie de <time.h> en utilisant #defines

Vous #import <time.h>:
Ne pas aller. Même si seulement une partie de <time.h> était déjà incluse,
En ce qui concerne #import, ce fichier est déjà complètement inclus.

Ligne de fond:

Les en-têtes C/C++ incluent traditionnellement parties d’autres fichiers d’inclusion.
Donc pour les en-têtes C/C++, utilisez #include.
Pour les en-têtes objc/objc ++, utilisez #import.

61
user512705

#include fonctionne exactement comme le C #include.

#import garde la trace des en-têtes déjà inclus et est ignoré si un en-tête est importé plusieurs fois dans une unité de compilation. Cela rend inutile l'utilisation de gardes d'en-tête.

En bout de ligne, utilisez simplement #import dans Objective-C et ne vous inquiétez pas si vos en-têtes finissent par importer quelque chose plus d'une fois.

22
Ferruccio

Je sais que ce fil est vieux ... mais dans les "temps modernes" .. il y a une stratégie "include" ("inclure la stratégie") bien supérieure à modules de @import de clang - qui est souvent négligée ..

Les modules améliorent l'accès à l'API des bibliothèques de logiciels en remplaçant le modèle d'inclusion de préprocesseur textuel par un modèle sémantique plus robuste et plus efficace. Du point de vue de l'utilisateur, le code semble légèrement différent, car on utilise une déclaration d'importation plutôt qu'une directive de préprocesseur #include:

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

ou

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

Cependant, cette importation de module se comporte différemment de la #include correspondante: lorsque le compilateur voit l'importation de module ci-dessus, il charge une représentation binaire du module et met son API à la disposition directe de l'application. Les définitions de préprocesseur qui précèdent la déclaration d'importation n'ont aucune incidence sur l'API fournie ... car le module lui-même a été compilé en tant que module séparé et autonome. En outre, tout indicateur de l'éditeur de liens requis pour utiliser le module sera automatiquement automatiquement fourni lors de l'importation du module. Ce modèle d'importation sémantique répond à de nombreux problèmes du modèle d'inclusion de préprocesseur.

Pour activer les modules, passez l'indicateur de ligne de commande -fmodules aka CLANG_ENABLE_MODULES dans Xcode- au moment de la compilation. Comme mentionné ci-dessus .. cette stratégie évite TOUT et TOUT LDFLAGS. Comme dans, vous pouvez SUPPRIMER tous les paramètres "OTHER_LDFLAGS", ainsi que toutes les phases "Liaison".

enter image description here

Je trouve que les temps de compilation/lancement sont "plus" agréables (ou peut-être qu'il y a moins de décalage lors de la "liaison"?) ... et offre également une excellente occasion de purger le fichier désormais superflu Project-Prefix.pch, et paramètres de construction correspondants, GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADER et GCC_PREFIX_HEADER, etc.

Aussi, même si cela n’est pas bien documenté… Vous pouvez créer module.maps pour vos propres frameworks et les inclure de la même manière pratique. Vous pouvez jeter un oeil à mon dépôt github ObjC-Clang-Modules pour quelques exemples sur la façon de mettre en œuvre de tels miracles.

13
Alex Gray

Si vous connaissez C++ et les macros, alors

#import "Class.h" 

est similaire à

{
#pragma once

#include "class.h"
}

ce qui signifie que votre classe ne sera chargée qu'une fois lors de l'exécution de votre application.

4
Evol Gate

La directive #import utilisée par Objective-C est presque identique au mécanisme classique #include dont elle a hérité du langage de programmation C. La seule différence est que cela garantit que le même fichier n'est jamais inclus plus d'une fois. Ceci est une petite commodité pour éviter la technique courante C d'inclure une protection d'en-tête pour le preprocessor.

Avoir le preprocessor (le préprocesseur offre la possibilité d'inclure des fichiers d'en-tête, des extensions de macros, une compilation conditionnelle et un contrôle de ligne.) Analyser chaque fichier d'en-tête dans chaque fichier source devient rapidement lent et inefficace à mesure que le Les fichiers source incluent les mêmes fichiers d'en-tête.

  1. #import garde la trace des en-têtes déjà inclus et est ignoré si un en-tête est importé plusieurs fois dans une unité de compilation. Cela rend inutile l'utilisation de gardes d'en-tête.

  2. Lorsque vous utilisez #import, l'en-tête include garde n'est pas nécessaire. Sinon, c’est comme #include.

  3. #include vous permet d'inclure plusieurs fois le même fichier.

La compilation d'un fichier en Objective-C s'effectue en deux passes. Tout d’abord, le préprocesseur parcourt le fichier. La sortie du préprocesseur va dans le compilateur réel.

tilisez @import à la place

1
yoAlex5

SI vous incluez un fichier deux fois dans des fichiers .h, le compilateur générera une erreur. Mais si vous importez un fichier plusieurs fois, le compilateur l'ignorera.

1
Husmukh

Dans le cas où j'avais une variable globale dans l'un de mes fichiers .h qui était à l'origine du problème, je l'ai résolue en ajoutant extern devant celui-ci.

1
Winston

#include il récupérait des "choses" d'un autre fichier à celui dans lequel le #include est utilisé. Ex:

dans le fichier: main.cpp

#include "otherfile.h"

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

La protection d'en-tête est utilisée en haut de chaque fichier d'en-tête (* .h) pour empêcher l'inclusion du même fichier plusieurs fois (si cela se produit, vous obtiendrez des erreurs de compilation).

dans le fichier: otherfile.h

#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif

même si vous mettez #include "autrefichier.h" n dans votre code, cette information ne sera pas redéclarée.

0
Celso Dantas