В чем разница между #import и #include в Objective-C?

Каковы различия между #import и #include в Objective-C и есть ли моменты, когда вы должны использовать один над другим? Один устарел?

Я читал следующий учебник: http://www.otierney.net/objective-c.html#preamble и его параграф о #import и #include, кажется, противоречит сам себе или, по крайней мере, неясен.

13.01.2009 16:25:17
10 ОТВЕТОВ
РЕШЕНИЕ

Директива #import была добавлена ​​в Objective-C как улучшенная версия #include. Однако все же вопрос о том, улучшился он или нет, все еще остается предметом дискуссий. #import гарантирует, что файл будет включен только один раз, чтобы у вас никогда не возникало проблем с рекурсивными включениями. Однако большинство приличных заголовочных файлов в любом случае защищают себя от этого, так что это не так уж и полезно.

По сути, вам решать, что вы хотите использовать. Я склонен #import заголовков для объектов Objective-C (таких как определения классов и тому подобное) и #include стандартные вещи C, которые мне нужны. Например, один из моих исходных файлов может выглядеть так:

#import <Foundation/Foundation.h>

#include <asl.h>
#include <mach/mach.h>
341
27.09.2014 19:05:13
Даже если в заголовочных файлах содержатся защитные элементы include, при компиляции все еще наблюдается снижение производительности, если вы используете #include - компилятор должен открыть каждый заголовочный файл, чтобы заметить защитные элементы include.
Matt Dillard 13.01.2009 16:41:36
защита заголовка - это директива препроцессора, обеспечивающая включение заголовка только один раз в исходный файл.
Jason Coco 15.01.2009 16:14:08
Я думаю, что #import на самом деле является дополнением GCC, а не Objective-C. Вы можете использовать его на языках, отличных от ObjC, если вы компилируете с GCC (или Clang)
Dave DeLong 1.12.2009 22:48:40
@dave - #import - это дополнение Objective-C к препроцессору. GCC поддерживает его только в исходных файлах C и C ++, хотя они официально предлагают не использовать его в C или C ++ в пользу переносимых традиционных средств защиты заголовков. Однако все препроцессоры Objective-C должны включать #import.
Jason Coco 2.12.2009 04:01:45
Защита заголовка - это то, где вы добавляете к вершине: #ifndef myheader #define myheader ... сопровождается кодом заголовка ...#endif
Tim 12.03.2012 16:36:00

#includeработает так же , как C #include.

#importотслеживает, какие заголовки уже включены, и игнорируется, если заголовок импортирован более одного раза в блок компиляции. Это делает ненужным использование охранников заголовка.

Суть в том, что вы используете #importObjective-C, и не беспокойтесь, если ваши заголовки импортируют что-то более одного раза.

23
13.01.2009 16:28:39
притворившись на минуту, что я не знаком с C #include (в основном потому, что я не знаком), в чем главное отличие #include от #import? Кроме того, вы можете сказать мне, что такое охрана заголовка?
Ryan Guill 13.01.2009 20:01:08
@ Райан: Посмотрите на ответ Свена.
Adrian Petrescu 17.09.2010 22:41:37

#includeраньше он получал «вещи» из другого файла в тот, #includeкоторый используется. Пример:

в файле: main.cpp

#include "otherfile.h"

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

Защита заголовка используется в верхней части каждого заголовочного файла (* .h), чтобы предотвратить включение одного и того же файла более одного раза (если это произойдет, вы получите ошибки компиляции).

в файле: otherfile.h

#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif

даже если вы #includeдобавите в свой код файл «otherfile.h» n раз, он не будет переопределен.

0
9.10.2011 01:03:19

Если вы #include файл два раза в файлах .h, чем компилятор выдаст ошибку. Но если вы #import файла более одного раза, компилятор будет игнорировать его.

0
16.07.2010 09:43:02
#includeодин и тот же файл дважды не приводит к ошибке.
kennytm 16.07.2010 09:45:37
В дополнение к комментарию @ KennyTM, # включение одного и того же файла дважды в один и тот же заголовок не приводит к ошибке компиляции, если имеются обычные заголовочные заголовки (#ifndef FILE_NAME_H #define FILE_NAME_H #end). Это ожидаемая практика. Использование #import для защиты заголовков не требуется.
jbat100 17.12.2012 11:16:32
@ jbat100: #includeэто просто механизм копирования и вставки. Преднамеренное использование #includeболее одного раза без включения охраны, например, «X macro».
kennytm 18.12.2012 05:46:50
Включение файла дважды может привести к ошибкам в зависимости от того, что вы включаете. Я видел C-код, который использовался #includeдля реализации своего рода шаблонов. Они сделали a #define, включили заголовок, #undefd и переделали #define, включили тот же заголовок во второй раз. Это привело к тому, что код был параметризован, действителен и включен дважды, так как значение определения было другим. Таким образом, у использования есть свои преимущества #include, но если вы используете современный язык, такой как C ++ или ObjC, вам это обычно не нужно.
uliwitness 12.08.2015 17:39:12

Кажется, есть много путаницы в отношении препроцессора.

Что делает компилятор, когда он видит, #includeчто он заменяет эту строку содержимым включенных файлов, без вопросов.

Итак, если у вас есть файл a.hс этим содержимым:

typedef int my_number;

и файл b.cс этим содержанием:

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

файл b.cбудет переведен препроцессором перед компиляцией в

typedef int my_number;
typedef int my_number;

что приведет к ошибке компилятора, так как тип my_numberопределяется дважды. Несмотря на то, что определение одно и то же, это не допускается языком Си.

Поскольку заголовок часто используется более чем в одном месте , в C обычно используются защитные элементы. Это выглядит так:

 #ifndef _a_h_included_
 #define _a_h_included_

 typedef int my_number;

 #endif

Файл b.cвсе равно будет содержать все содержимое заголовка дважды после предварительной обработки. Но второй экземпляр будет проигнорирован, поскольку макрос _a_h_included_уже будет определен.

Это работает очень хорошо, но имеет два недостатка. Прежде всего, должны быть включены защитные элементы, а имя макроса должно быть разным в каждом заголовке. И, во-вторых, компилятор все еще должен искать заголовочный файл и читать его так часто, как он включен.

Objective-C имеет #importинструкцию препроцессора (ее также можно использовать для кода C и C ++ с некоторыми компиляторами и опциями). Это делает почти то же самое #include, но также отмечает, какой файл уже был включен. #importЛиния заменяется только содержимое указанного файла в первый раз она встречается. Каждый раз после этого это просто игнорируется.

358
17.09.2010 22:38:15
Это лучший ответ, чем принятый. @Guill, вы должны изменить принятый ответ.
Nguyen Minh Binh 3.01.2013 09:18:58
После изменения 4 #includeс на #imports в заголовочном файле шаблона с 7000 строк заметно улучшается производительность компиляции и отзывчивость XCode intellisense. (Я не думаю, что я себе это представляю)
bobobobo 13.08.2013 18:42:15

Я согласен с Джейсоном.

Я был пойман, делая это:

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

Для GNU gcc он продолжал жаловаться, что функция time () не была определена.

Тогда я изменил #import на #include и все прошло нормально.

Причина:

Вы #import <sys / time.h>:
    <sys / time.h> включаете только часть <time.h>, используя #defines

Вы #import <time.h>:
    нет. Хотя
    в отношении #import уже была включена только часть <time.h> , этот файл уже полностью включен.

Нижняя граница:

Заголовки C / C ++ традиционно включают в себя части других включаемых файлов.
Так что для заголовков C / C ++ используйте #include.
Для заголовков objc / objc ++ используйте #import.

62
11.07.2013 18:49:57
Кажется, что у Clang нет этой не определенной проблемы.
ooops 23.02.2017 08:37:01

Если вы знакомы с C ++ и макросами, тогда

#import "Class.h" 

похоже на

{
#pragma once

#include "class.h"
}

Это означает, что ваш класс будет загружен только один раз при запуске приложения.

4
18.10.2012 13:01:22
Это поддерживаемое использование #pragma один раз? Я всегда думал , прагму необходимое , чтобы быть внутри в ВКЛЮЧАЕТ ред файла на работу.
uliwitness 12.08.2015 17:33:41
@uliwitness Вы правы. #pragma onceпомещается во включаемый файл, а не в файл, который выполняет включение. -1 за это.
herzbube 22.06.2016 13:10:45

Я знаю, что эта ветка старая ... но в "современную эпоху" ... гораздо лучше "включить стратегию" через модули Clang@import - это часто упускается из виду ...

Модули улучшают доступ к API библиотек программного обеспечения, заменяя модель включения текстового препроцессора более надежной, более эффективной семантической моделью. С точки зрения пользователя, код выглядит немного иначе, потому что используется декларация импорта, а не директива препроцессора #include:

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

или

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

Однако этот импорт модуля ведет себя совершенно иначе, чем соответствующий #include: когда компилятор видит импорт модуля выше, он загружает двоичное представление модуля и делает его API доступным для приложения напрямую. Определения препроцессора, предшествующие объявлению импорта, не влияют на предоставляемый API ... потому что сам модуль был скомпилирован как отдельный, автономный модуль. Кроме того, любые флаги компоновщика, необходимые для использования модуля, будут автоматически предоставлены при импорте модуля. Эта семантическая модель импорта решает многие проблемы модели включения препроцессора.

Чтобы включить модули, передайте флаг командной строки -fmodulesaka CLANG_ENABLE_MODULESin Xcode- во время компиляции. Как упомянуто выше .. эта стратегия устраняет ЛЮБОЕ и ВСЕ LDFLAGS. Например, вы можете УДАЛИТЬ любые настройки «OTHER_LDFLAGS», а также любые фазы «Связывания».

введите описание изображения здесь

Я нахожу, что время компиляции / запуска «чувствует» намного быстрее (или, может быть, при «связывании» меньше задержки), а также предоставляет отличную возможность удалить теперь посторонний файл Project-Prefix.pch, и соответствующие параметры сборки, GCC_INCREASE_PRECOMPILED_HEADER_SHARING, GCC_PRECOMPILE_PREFIX_HEADER, и GCC_PREFIX_HEADERт.д.

Кроме того, хотя они недостаточно хорошо документированы ... Вы можете создавать module.maps для своих собственных фреймворков и включать их таким же удобным способом. Вы можете взглянуть на мой репозиторий ObjC-Clang-Modules github для некоторых примеров того, как реализовать такие чудеса.

13
18.04.2014 01:37:44

В одном случае у меня была глобальная переменная в одном из моих .hфайлов, которая вызывала проблему, и я решил ее, добавив externперед ней.

1
10.08.2015 15:47:32
#include + guard == #import

#include guardWiki - защита от макросов, защита заголовков или защита файлов предотвращает двойное включение заголовка,preprocessorчто может замедлить время сборки

Следующий шаг

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

[# импорт в .hили .m]

0
15.04.2020 11:58:48