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

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

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

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
390
0
138 052
10
Перейти к ответу Данный вопрос помечен как решенный

Ответы 10

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

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

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

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

Ryan Guill 13.01.2009 23:01

@ Райан: Посмотри на ответ Свена.

Adrian Petrescu 18.09.2010 02:41
Ответ принят как подходящий

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

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

#import <Foundation/Foundation.h>

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

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

Matt Dillard 13.01.2009 19:41

защита заголовка - это директива препроцессора, которая гарантирует, что заголовок включается в исходный файл только один раз.

Jason Coco 15.01.2009 19:14

Я думаю, что #import на самом деле является дополнением GCC, а не Objective-C. Вы можете использовать его на языках, отличных от ObjC, если вы компилируете с GCC (или Clang)

Dave DeLong 02.12.2009 01:48

@dave - #import - это дополнение Objective-C к препроцессору. GCC просто поддерживает его в исходных файлах C и C++, хотя официально предлагает не использовать его в C или C++ в пользу переносимых традиционных средств защиты заголовков. Однако все препроцессоры Objective-C должны включать #import.

Jason Coco 02.12.2009 07:01

Защита заголовка - это то место, где вы добавляете вверху: #ifndef myheader #define myheader ... с последующим кодом заголовка ... #endif

Tim 12.03.2012 20:36

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

aroth 24.01.2013 04:10

@aroth: Дело не в том, что новее или старше. Речь идет о стандартном и нестандартном.

Chuck 07.03.2013 05:18

@ Чак - Возможно. Но стандарт, который не развивается и рекомендует устаревшие, неуклюжие и тупые способы делать что-то, на мой взгляд, не очень ценен. Особенно, когда возможности инструментов делать развиваются, и вдвойне, когда «все препроцессоры Objective-C должны включать #import» и когда мы говорим о коде в контексте проекта Objective-C.

aroth 07.03.2013 07:32

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

gnasher729 24.02.2014 00:46

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

Steven Fisher 16.04.2014 05:42

Следует также отметить, что C++ имеет другой подход, в котором вы используете #pragma once вместо ручных средств защиты заголовков. Таким образом, C++ по-прежнему использует #include, но также решает проблему, которую призван решить #import.

uliwitness 12.08.2015 20:31

@ gnasher729 Верно, это называется Оптимизация с несколькими включениями и позволяет избежать ненужного повторного открытия файла.

Bilow 15.12.2016 23:47

Хорошая особенность #import, о которой здесь, кажется, никто не упоминает, заключается в том, что это единственное решение, не требующее дополнительного кода. В любом случае это не так много кода, но обычно лучше меньше кода для одного и того же. Также немного снижает планку для новых разработчиков, которые могут не знать о щитках заголовков или #pragma once.

William T Froggard 15.05.2018 22:20

#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" один раз в свой код, он не будет повторно объявлен.

ЕСЛИ вы # включаете файл два раза в файлы .h, компилятор выдаст ошибку. Но если вы # импортируете файл более одного раза, компилятор проигнорирует его.

#include один и тот же файл дважды не приводит к ошибке.
kennytm 16.07.2010 13:45

Чтобы дополнить комментарий @KennyTM, # включение одного и того же файла дважды в один и тот же заголовок не приводит к ошибке компиляции, ЕСЛИ присутствуют обычные заголовки (#ifndef FILE_NAME_H #define FILE_NAME_H #end). Это ожидаемая практика. Использование #import не требует защиты заголовков.

jbat100 17.12.2012 15:16

@ jbat100: #include - это просто механизм копирования и вставки. #include преднамеренно используется более одного раза без защитных приспособлений, например «макрос X».

kennytm 18.12.2012 09:46

Включение файла дважды май приводит к ошибкам в зависимости от того, что вы включаете. Я видел код C, который использовал #include для реализации своего рода шаблонов. Они сделали #define, включили заголовок, #undefd и переделали #define, включили тот же заголовок во второй раз. Это привело к тому, что код был параметризован, действителен и включен дважды, поскольку значение определения было другим. Таким образом, у использования #include есть свои преимущества, но если вы используете современный язык, такой как C++ или ObjC, вам это обычно не нужно.

uliwitness 12.08.2015 20:39

Похоже, существует большая путаница в отношении препроцессора.

Что делает компилятор, когда видит #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.

Поскольку заголовок часто используется более чем в одном месте, включить охранников обычно используются в 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 заменяется содержимым указанного файла только при первом обнаружении. Каждый раз после этого просто игнорируется.

Это лучший ответ, чем принятый. @Guill, вы должны изменить принятый ответ.

Nguyen Minh Binh 03.01.2013 13:18

После замены 4 #include на #import в файле заголовка шаблона из 7000 строк наблюдается заметное улучшение производительности компиляции и отзывчивости XCode intellisense. (Не думаю, что я это себе представляю)

bobobobo 13.08.2013 22:42

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

Меня поймали на этом:

#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> с помощью # define

Вы #import <time.h>:
    Нет. Несмотря на то, что только часть <time.h> уже была включена, as
    far, что касается #import, этот файл теперь уже полностью включен.

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

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

Кажется, что у clang нет этой неопределенной проблемы.

ooops 23.02.2017 11:37

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

rambo 09.08.2020 21:53

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

#import "Class.h" 

похоже на

{
#pragma once

#include "class.h"
}

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

Поддерживается ли это однократное использование #pragma? Я всегда думал, что для работы прагма должна быть внутри, файл includeред.

uliwitness 12.08.2015 20:33

@uliwitness Вы правы. #pragma once помещается во включенный файл, а не в файл, который выполняет включение. -1 за это.

herzbube 22.06.2016 16:10

Я знаю, что эта ветка устарела ... но в "современное время" ... существует гораздо более совершенная "стратегия включения" через модули clang's @import - это часто упускается из виду ..

Modules improve access to the API of software libraries by replacing the textual preprocessor inclusion model with a more robust, more efficient semantic model. From the user’s perspective, the code looks only slightly different, because one uses an import declaration rather than a #include preprocessor directive:

@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>

However, this module import behaves quite differently from the corresponding #include: when the compiler sees the module import above, it loads a binary representation of the module and makes its API available to the application directly. Preprocessor definitions that precede the import declaration have no impact on the API provided... because the module itself was compiled as a separate, standalone module. Additionally, any linker flags required to use the module will automatically be provided when the module is imported. This semantic import model addresses many of the problems of the preprocessor inclusion model.

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

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

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

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

#include + guard == #import

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

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

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

[#import in .h или .m]

Другие вопросы по теме