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

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

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

9 ответов


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

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

#import <Foundation/Foundation.h>

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

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

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

так что если у вас есть файл a.h С таким содержанием:

typedef int my_number;

и С таким содержанием:

#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_ уже определены.

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

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


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

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

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

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

Итак, я изменил #import на #include, и все прошло хорошо.

причина:

вы #import в:
    в включает только a часть в с помощью #defines

вы #import в:
    Бесполезный. Хотя только часть уже был включен, как
    что касается #import, этот файл теперь уже полностью включено.

итог:

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


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

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

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


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

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

@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 ака CLANG_ENABLE_MODULES на Xcode- во время компиляции. Как упоминалось выше.. эта стратегия устраняет все LDFLAGS. Как и в, ВЫ можете удалить любые " OTHER_LDFLAGS" настройки, а также любые фазы "связывания"..

enter image description here

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

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


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

#import "Class.h" 

похож на

{
#pragma once

#include "class.h"
}

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


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


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


#include он использовал, чтобы получить "вещи" из другого файла в тот #include используется в. Ex:

in file: main.cpp

#include "otherfile.h"

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

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

in file: otherfile.h

#ifndef OTHERFILE
#define OTHERFILE

// declare functions, classes or objects here

#endif

даже если вы положите #include "otherfile.h " N время в вашем коде, это внутри него не будет быть объявленным заново.