В чем разница между @class и #import - PullRequest
7 голосов
/ 29 июля 2010

Когда я компилирую со следующим кодом, ошибок нет:

@class RootViewController;
//#import "RootViewController.h"

Когда я компилирую со следующим кодом, я получаю ошибку:

//@class RootViewController;
#import "RootViewController.h"

"ошибка: ожидаемый спецификатор-qualifier-list before 'RootViewController' "

Я не понимаю, в чем разница между ними, потому что я использовал #import в похожем классе, и он скомпилирован без ошибок!

Ответы [ 8 ]

25 голосов
/ 29 июля 2010

@class используется, когда вам нужно знать имя класса в определенном файле, но вам не нужно знать подробности о классе (например, его методах).#import используется, когда вам действительно нужно использовать класс (т. Е. Отправить ему сообщение).

Например, если вы объявляете переменные экземпляра в заголовочном файле, выможно использовать @class для объявления переменной экземпляра определенного типа:

@class MyOtherClass;

@interface MyClass : NSObject
{
    MyOtherClass *myIvar;
}
@end

Поскольку вы еще не используете myIvar, вам ничего не нужно знать об этом, за исключением того, что тип MyOtherClass существует.

Однако:

#import "MyOtherClass.h"

- (void)doSomething
{
    [myIvar doSomethingElse];
}

В этом случае вы отправляете сообщение doSomethingElse на myIvar;компилятор должен знать, что экземпляры MyOtherClass определяют этот метод, поэтому вам нужно импортировать файл заголовка, иначе компилятор будет жаловаться.

Зачем беспокоиться об этом?

Это в основном связано с зависимостями.Когда вы #import файла A в файл B, файл B становится зависимым от файла A - то есть, если файл A изменяется, вам придется перекомпилировать файл B. Если вы используете @class вфайл B, файл B не зависит от файла A и, следовательно, не нуждается в перекомпиляции при изменении файла A - поэтому, если вы просто объявляете тип и фактически не зависит от реализации файла A, вы можете сохранитьвремя компиляции не #import в файле А.

8 голосов
/ 29 июля 2010

Я решил обратиться к документации, потому что все еще был в замешательстве:

# импорт

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

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

@ класс

Подобные объявления просто используют имя класса в качестве типа и не зависят от каких-либо деталей интерфейса класса (его методов и переменных экземпляра), директива @class дает компилятору достаточное предупреждение о том, чего ожидать. Однако если интерфейс к классу фактически используется (созданные экземпляры, отправленные сообщения), интерфейс класса должен быть импортирован.

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF123

6 голосов
/ 29 июля 2010

Основное правило: используйте @class в заголовочном файле и #import в файле реализации.(Однако вам нужно #import ваш класс 'суперкласс. И в некоторых других случаях вам также нужно использовать `#import' в заголовке.)

#import не эквивалентно #include.Если файл included много раз, он будет загружаться каждый раз, но со многими #imports одного и того же файла он все равно будет загружен только один раз.

Поэтому основная причина использования @class не для того, чтобы избежать циклических зависимостей, а для ускорения компиляции.

Вот пример, когда вы должны использовать @class

//MYControl.h

@class MYControl;  // Must use class

@protocol MYControlDelegate
-(void)control:(MYControl *)control didChangeToState:(UIControlState)state;
@end

@interface MYControl : UIControl
{
   id<MYControlDelegate> delegate_;
}
@property (nonatomic, assign) id<MYControlDelegate> delegate;
@end

//MYControl.m

@implementation MYControl
@synthesize delegate = delegate_;
. . .

В этом случае, нечего импортировать, потому что протокол делегата объявлен над основным классом в заголовочном файле. Но вам все еще нужно иметь возможность ссылаться на основной класс, который еще не был объявлен. Так что @class делает, чтобыпросто сообщите компилятору, что существует некоторый класс, который называется MYControl и будет определен в какой-то момент (однако не во время выполнения. Класс будет определен в процессе компиляции.)

РЕДАКТИРОВАТЬ: От тРуководство по Objective-C:

Поскольку такие объявления просто используют имя класса в качестве типа и не зависят от каких-либо деталей интерфейса класса (его методов и переменных экземпляра), класс @classДиректива дает компилятору достаточное предупреждение о том, чего ожидать.Однако, если интерфейс к классу фактически используется (созданные экземпляры, отправленные сообщения), интерфейс класса должен быть импортирован.Как правило, интерфейсный файл использует @class для объявления классов, а соответствующий файл реализации импортирует их интерфейсы (поскольку ему потребуется создавать экземпляры этих классов или отправлять им сообщения).

Директива @class минимизирует количествокода, видимого компилятором и компоновщиком, и, следовательно, является самым простым способом дать прямое объявление имени класса.Проще говоря, это позволяет избежать потенциальных проблем, которые могут возникнуть при импорте файлов, импортирующих еще другие файлы.Например, если один класс объявляет статически типизированную переменную экземпляра другого класса, и их два интерфейсных файла импортируют друг друга, ни один класс не может скомпилироваться правильно.

Обратите внимание, что в последнем предложении цикличность упоминается какодин из общего класса проблем, решаемых с помощью @class.

6 голосов
/ 29 июля 2010

@class используется, чтобы избежать циклической зависимости ... Это предотвращает циклические ссылки, когда в один заголовок A импортируется второй заголовок B, который (B) импортирует первый (A), который импортирует второй (B) и так далеебесконечный цикл .... @class обычно используется, чтобы попросить компилятор искать его определение во время выполнения ... особенно, когда он находится в некоторой статической библиотеке ..

Кроме этого #import работает

См. Этот вопрос

2 голосов
/ 12 июля 2014

@ class: - Он определяет, что вы можете создать переменную экземпляра импортированного класса и использовать ее в своем классе.

import: - Определяет, что вы можете получить доступ к переменным, объявленным в требуемом импортируемом классе.

Вы можете использовать данную ссылку для получения дополнительной информации.

http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF123

0 голосов
/ 29 сентября 2015

@ class - это предварительное объявление, хорошей практикой является размещение их в .h вместо #import во избежание циклической проблемы #import.

0 голосов
/ 13 февраля 2013

вы должны импортировать этот класс в класс, в который вы хотите импортировать здесь. Вот почему вы получаете ошибку, но ее можно исправить на примере @class.

0 голосов
/ 29 июля 2010

@class означает, что определение класса RootViewController еще не объявлено, но будет определено во время выполнения.Я полагаю, что это похоже на объявление внешнего класса в c ++.

#import эквивалентно # include.

сообщением об ошибке. Я могу догадаться, что вы только что допустили ошибку где-то внутри RootViewController.hтипа забытого;или что-то в этом роде

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...