Каково различие между @class и #import

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

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

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

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

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

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

8
задан TheLearner 29 July 2010 в 11:04
поделиться

5 ответов

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

#import

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

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

@class

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

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

8
ответ дан 5 December 2019 в 04:36
поделиться

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

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

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

6
ответ дан 5 December 2019 в 04:36
поделиться

@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 файл A.

25
ответ дан 5 December 2019 в 04:36
поделиться

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

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

Поэтому основная причина использования @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 и будет определен в какой-то момент. (Однако не во время выполнения. Класс будет определен в процессе компиляции.)

EDIT: Из руководства по Objective-C:

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

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

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

7
ответ дан 5 December 2019 в 04:36
поделиться

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

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

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

.
0
ответ дан 5 December 2019 в 04:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: