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





#include работает так же, как C #include.
#import отслеживает, какие заголовки уже были включены, и игнорируется, если заголовок импортируется более одного раза в единицу компиляции. Это делает ненужным использование защиты жатки.
Суть в том, что просто используйте #import в Objective-C и не беспокойтесь, если ваши заголовки импортируют что-то более одного раза.
@ Райан: Посмотри на ответ Свена.
Директива #import была добавлена в Objective-C как улучшенная версия #include. Однако вопрос о том, улучшился он или нет, все еще остается предметом споров. #import гарантирует, что файл всегда включается только один раз, так что у вас никогда не будет проблем с рекурсивным включением. Однако большинство приличных файлов заголовков в любом случае защищают себя от этого, так что на самом деле это не так уж и важно.
По сути, вам решать, что именно вы хотите использовать. Я стараюсь # импортировать заголовки для вещей Objective-C (например, определения классов и т. д.) И # включать стандартные материалы C, которые мне нужны. Например, один из моих исходных файлов может выглядеть так:
#import <Foundation/Foundation.h>
#include <asl.h>
#include <mach/mach.h>
Даже если файлы заголовков содержат средства защиты включения, при использовании #include производительность компиляции все равно снижается - компилятор должен открывать каждый файл заголовка, чтобы заметить средства защиты включения.
защита заголовка - это директива препроцессора, которая гарантирует, что заголовок включается в исходный файл только один раз.
Я думаю, что #import на самом деле является дополнением GCC, а не Objective-C. Вы можете использовать его на языках, отличных от ObjC, если вы компилируете с GCC (или Clang)
@dave - #import - это дополнение Objective-C к препроцессору. GCC просто поддерживает его в исходных файлах C и C++, хотя официально предлагает не использовать его в C или C++ в пользу переносимых традиционных средств защиты заголовков. Однако все препроцессоры Objective-C должны включать #import.
Защита заголовка - это то место, где вы добавляете вверху: #ifndef myheader #define myheader ... с последующим кодом заголовка ... #endif
Итак, официальная рекомендация - избегать использования более новых, простых и лучших вещей ради сохранения совместимости со старыми вещами, которые можно так же легко обновить для поддержки нового ключевого слова? Это чепуха. Кому-то нужно привести новых чиновников.
@aroth: Дело не в том, что новее или старше. Речь идет о стандартном и нестандартном.
@ Чак - Возможно. Но стандарт, который не развивается и рекомендует устаревшие, неуклюжие и тупые способы делать что-то, на мой взгляд, не очень ценен. Особенно, когда возможности инструментов делать развиваются, и вдвойне, когда «все препроцессоры Objective-C должны включать #import» и когда мы говорим о коде в контексте проекта Objective-C.
В приличном компиляторе защита включения не требует затрат во время компиляции. Заголовочный файл необходимо включить один раз, если вы хотите его использовать. Когда он включен, компилятор обнаружит защиту заголовка. и запомни это. Во втором #include для того же файла компилятор знает о защите заголовка и даже не смотрит на файл.
Это не стандартное против нестандартного; это язык против языка, и одно намерение против другого. Если вы используете Objective-C а также, вы собираетесь использовать включить заголовок Objective-C, используйте #import. Если вы используете C, C++ или же использует Objective-C и просто хочет встроить один файл в другой, используйте #include.
Следует также отметить, что C++ имеет другой подход, в котором вы используете #pragma once вместо ручных средств защиты заголовков. Таким образом, C++ по-прежнему использует #include, но также решает проблему, которую призван решить #import.
@ gnasher729 Верно, это называется Оптимизация с несколькими включениями и позволяет избежать ненужного повторного открытия файла.
Хорошая особенность #import, о которой здесь, кажется, никто не упоминает, заключается в том, что это единственное решение, не требующее дополнительного кода. В любом случае это не так много кода, но обычно лучше меньше кода для одного и того же. Также немного снижает планку для новых разработчиков, которые могут не знать о щитках заголовков или #pragma once.
#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, # включение одного и того же файла дважды в один и тот же заголовок не приводит к ошибке компиляции, ЕСЛИ присутствуют обычные заголовки (#ifndef FILE_NAME_H #define FILE_NAME_H #end). Это ожидаемая практика. Использование #import не требует защиты заголовков.
@ jbat100: #include - это просто механизм копирования и вставки. #include преднамеренно используется более одного раза без защитных приспособлений, например «макрос X».
Включение файла дважды май приводит к ошибкам в зависимости от того, что вы включаете. Я видел код C, который использовал #include для реализации своего рода шаблонов. Они сделали #define, включили заголовок, #undefd и переделали #define, включили тот же заголовок во второй раз. Это привело к тому, что код был параметризован, действителен и включен дважды, поскольку значение определения было другим. Таким образом, у использования #include есть свои преимущества, но если вы используете современный язык, такой как C++ или ObjC, вам это обычно не нужно.
Похоже, существует большая путаница в отношении препроцессора.
Что делает компилятор, когда видит #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, вы должны изменить принятый ответ.
После замены 4 #include на #import в файле заголовка шаблона из 7000 строк наблюдается заметное улучшение производительности компиляции и отзывчивости XCode intellisense. (Не думаю, что я это себе представляю)
Я согласен с Джейсоном.
Меня поймали на этом:
#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 нет этой неопределенной проблемы.
Это действительно отличный пример того, почему сложно незаметно внедрить современные функции (#import) в существующие системы. Если системные библиотеки будут обновлены, чтобы лучше обрабатывать #import ... вероятно, нет. Если бы это было так, то это было бы за счет многих существующих проектов, которые сознательно или неосознанно полагаются на существующее поведение. Если в процессе разработки языков перестанут появляться новые полезные и перспективные функции ... нет. Итак, это никогда не бывает так просто, как предполагают некоторые комментарии к принятому ответу.
Если вы знакомы с C++ и макросами, то
#import "Class.h"
похоже на
{
#pragma once
#include "class.h"
}
Это означает, что ваш класс будет загружен только один раз при запуске вашего приложения.
Поддерживается ли это однократное использование #pragma? Я всегда думал, что для работы прагма должна быть внутри, файл includeред.
@uliwitness Вы правы. #pragma once помещается во включенный файл, а не в файл, который выполняет включение. -1 за это.
Я знаю, что эта ветка устарела ... но в "современное время" ... существует гораздо более совершенная "стратегия включения" через модули 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, что может замедлить время сборки
Следующий шаг
[#import in .h или .m]
притворившись на минуту, что я не знаком с C#include (в основном потому, что я не знаком), в чем основное различие между #include и #import? Кроме того, можете ли вы сказать мне, что такое защита заголовка?