Мой запрос таков. Когда каждый использует #import и когда один использует @class?
Простой ответ: вы #import
или #include
когда есть физическая зависимость. В противном случае, можно использовать вперед деклараций ( @class MONClass
, struct MONStruct
,@protocol MONProtocol
).
Вот несколько распространенных примеров физической зависимости:
- Любое значение C или C ++ (указатель или ссылка не является физической зависимостью). Если у вас есть
CGPoint
как ivar или свойство, компилятор должен увидеть объявлениеCGPoint
.
- Ваш суперкласс.
- Метод, который вы используете.
Иногда, если я использую объявление @class, я вижу общее предупреждение компилятора, например: «предупреждение: получатель« FooController »является классом пересылки, и соответствующий @interface может не существовать».
Компилятор на самом деле очень снисходителен в этом отношении. Он будет сбрасывать подсказки (например, приведенные выше), но вы можете легко испортить свой стек, если проигнорируете их и не сделаете #import
правильно. Хотя это должно (IMO), компилятор не обеспечивает это. В ARC компилятор более строг, потому что он отвечает за подсчет ссылок. Что происходит, так это то, что компилятор возвращается к значению по умолчанию, когда он встречает неизвестный метод, который вы вызываете. Каждое возвращаемое значение и параметр предполагается равным id
. Таким образом, вы должны исключить каждое предупреждение из ваших кодовых баз, потому что это следует рассматривать как физическую зависимость. Это аналогично вызову функции C, которая не объявлена. С C параметры предполагаются равными int
.
Причина, по которой вы бы предпочли предварительные декларации, заключается в том, что вы можете сократить время сборки за счет факторов, поскольку зависимость минимальна. С помощью предварительных объявлений компилятор видит, что есть имя, и может правильно анализировать и компилировать программу, не видя объявления класса или всех его зависимостей, когда нет физической зависимости. Чистые сборки занимают меньше времени. Инкрементные сборки занимают меньше времени. Конечно, в конечном итоге вы потратите немного больше времени на то, чтобы все заголовки, которые вам нужны, были видны для каждого перевода, как следствие, но это быстро окупается за меньшее время сборки (если ваш проект не крошечный).
Если вы используете #import
или #include
вместо этого, вы тратите на компилятор гораздо больше работы, чем необходимо. Вы также вводите сложные зависимости заголовка. Вы можете сравнить это с алгоритмом грубой силы. Когда ты#import
, вы таскаете тонны ненужной информации, которая требует много памяти, дискового ввода-вывода и процессора для анализа и компиляции источников.
ObjC довольно близок к идеалу для языка на основе C в отношении зависимости, потому что NSObject
типы никогда не являются значениями -NSObject
типы всегда являются указателями с подсчетом ссылок. Таким образом, вы можете получить невероятно быстрое время компиляции, если вы правильно структурируете зависимости вашей программы и, по возможности, продвигаетесь вперед, потому что требуется очень мало физической зависимости. Вы также можете объявить свойства в расширениях класса для дальнейшей минимизации зависимости. Это большой бонус для больших систем - вы бы знали разницу, если бы вы когда-либо разрабатывали большую кодовую базу C ++.
Поэтому я рекомендую использовать форвардов, где это возможно, а затем туда, #import
где есть физическая зависимость. Если вы видите предупреждение или другое, которое подразумевает физическую зависимость - исправьте их все. Исправление #import
в вашем файле реализации.
Когда вы создаете библиотеки, вы, вероятно, классифицируете некоторые интерфейсы как группу, и в этом случае вы будете использовать #import
ту библиотеку, в которой вводится физическая зависимость (например #import <AppKit/AppKit.h>
). Это может привести к зависимости, но сопровождающие библиотеки часто могут обрабатывать физические зависимости по мере необходимости - если они вводят функцию, они могут минимизировать влияние, которое она оказывает на ваши сборки.