Nano Hash - криптовалюты, майнинг, программирование

В чем разница между @class и #import

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

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

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

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

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

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

29.07.2010

  • В вашем случае что-то не так в вашем файле RootViewController.h или в одном из файлов, которые он импортирует. Может, пропал без вести; где-то. К сожалению, отлаживать файлы заголовков немного сложно, потому что вы часто получаете ошибку в другом файле. Причина, по которой вы не получаете сообщение об ошибке при использовании @class, заключается в том, что он не загружает файл, содержащий ошибку. См. Мой ответ для более подробной информации. 29.07.2010
  • возможный дубликат Objective-C @class vs. #import 29.07.2010

Ответы:


1

@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, вы можете сэкономить время компиляции не #importing файл A.

29.07.2010

2

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

#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

29.07.2010
  • Кстати, если вам интересно, почему я не принял ответ - это потому, что эта система не позволяет мне принимать ответы до тех пор, пока не пройдет 2 дня - бог знает, зачем это нужно 30.07.2010

  • 3

    Основное правило: используйте @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.

    29.07.2010
  • Почему вы говорите, что @class не должен избегать циклических зависимостей, а затем предоставить пример, в котором он используется именно таким образом? В вашем примере класс MyControl зависит от протокола MyControlDelegate, а MyControlDelegate имеет зависимость от MyControl. 29.07.2010
  • Кстати, ваши объявления переменных и свойств типа делегата неверны. Они должны быть такими: id<MyControlDelegate> delegate_; 29.07.2010
  • @JeremyP: о декларации ivar / property: спасибо, я исправил. Что касается проблемы замкнутости, я сказал, что циклические ссылки не являются основной причиной существования @class. Скорее цель @class - уменьшить количество ссылок любого типа для ускорения компиляции. Циркулярные ссылки также можно обрабатывать другими способами, хотя @class тоже удобен в этом отношении. Думаю, эти утверждения отражены в цитате, которую я добавил к своему ответу. Указав на это, ничто не мешает мне показать пример, в котором @class помогает справиться с циклической ссылкой (в одном файле). 30.07.2010
  • Думаю, ты ошибаешься. Скорость компиляции - это не причина, о которой я когда-либо слышал раньше для использования @class. Возможно, вы сможете процитировать. 31.07.2010
  • Скорость компиляции - это самая важная причина, по которой я слышал использование @class. 03.08.2010

  • 4

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

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

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

    29.07.2010
  • Я не согласен с тем, что @class в основном используется, чтобы избежать циклических ссылок, потому что #import уже позаботился об этом. (Попробуй!) 29.07.2010
  • хорошо, несогласие принято ... @class обычно используется, чтобы попросить компилятор искать его определение во время выполнения ... особенно когда он находится в какой-то статической библиотеке ... 29.07.2010
  • @Felixyz: извините, но вы ошибаетесь. Основное использование @class - избежать циклической зависимости определений @interface и @protocol. 29.07.2010
  • @JeremyP: Я был неправ, говоря, что #import уже позаботился об этом, потому что это не всегда. Однако я считаю преувеличением сказать, что определения @protocol - это основное использование @class. В цитате, которую я добавил в свой ответ, например, нет упоминания @protocol. 30.07.2010
  • @Felixyz: Я не это имел в виду. Я имел в виду, что использование @class заключается в том, чтобы избежать циклических зависимостей @interfaces, а также, чтобы избежать циклических зависимостей @protocols и их комбинаций. 31.07.2010
  • Это основное использование, я использовал только #import и игнорировал @class, пока у меня не возникли проблемы с циклическим импортом. 06.04.2013

  • 5

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

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

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

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

    12.07.2014

    6

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

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

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

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

  • 7

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

    13.02.2013

    8

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

    29.09.2015
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..