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

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

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

Ответ 1

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

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

#import <Foundation/Foundation.h>

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

Ответ 2

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

Что делает компилятор, когда видит #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 и С++ с некоторыми компиляторами и опциями). Это почти то же самое, что и #include, но он также отмечает внутренне, какой файл уже включен. Строка #import заменяется только содержимым указанного файла в первый раз, когда оно встречается. Каждый раз после этого его просто игнорируют.

Ответ 3

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

Я поймал это:

#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 > включает только часть of < time.h > с помощью #defines

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

Нижняя строка:

Заголовки

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

Ответ 4

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

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

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

Ответ 5

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

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

enter image description here

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

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

Ответ 6

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

#import "Class.h" 

похож на

{
#pragma once

#include "class.h"
}

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

Ответ 7

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

Ответ 8

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

Ответ 9

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

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

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

  2. При использовании #import защита заголовка не требуется. В противном случае это так же, как #include.

  3. #include позволяет включать один и тот же файл много раз.

Компиляция файла в Objective-C выполняется в два этапа. Первый, препроцессор запускает файл. Выходные данные препроцессора поступают в реальный компилятор.

Используйте вместо этого @import

Ответ 10

#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 время в свой код, это внутри него не будет обновлено.