Цель C: свойства, не найденные в прямом объявлении, по сравнению с проблемой синтаксического анализа: ожидаемый тип

У меня есть одноэлементный класс под названием DataManager. Этот класс используется несколькими другими классами для загрузки и сохранения файлов plist.

Я добавляю возможность для DataManager сохранять снимки экрана, а также файлы plist. Для этого мне необходимо загрузить представление, снимок экрана которого я хочу сделать. Представление, которое я загружаю, поступает от контроллера, который импортирует DataManager.

Очевидно, это круговая зависимость, поэтому я использовал:

@class GardenView;

Однако это привело к следующим ошибкам:

  • Получатель GardenView для сообщения класса является предварительным объявлением
  • Тип получателя "GardenView", например, сообщение является пересылаемым.
  • объявление Свойство 'bounds' не может быть найдено в форвардном классе
  • объект 'GardenView' Свойство 'слой' не может быть найден в объекте прямого класса 'GardenView'

Похоже, он не может найти свойства, унаследованные от суперкласса UIView. Верно ли это для объявлений прямого класса?

Если я использую стандартный #import вместо @class, я получаю:

  • Проблема синтаксического анализа: ожидаемый тип

для методов в GardenView, ссылающихся на Plant (которые я просто импортирую):

- (void) addPlantToView: (Plant*) plant;
- (void) addPlantToGarden: (Plant*) plant;
- (void) addPlantToViewAndGarden: (Plant*) plant;

Класс Plant ДЕЙСТВИТЕЛЬНО импортирует DataManager, но если я изменю его на @class, я получу:

  • Нет известного метода класса для селектора sharedDataManager

Какое решение этой проблемы? Метод класса находится в файле заголовка (+ sharedDataManager). Я что-то делаю совершенно не так?


person J.R.    schedule 10.12.2012    source источник


Ответы (1)


Вы не прояснили, где именно вы выполняете импорт по сравнению с @class. И я думаю, что это вызывает недоумение. Вот что вы хотите сделать:

  • В GardenView.h используйте @class Plant
  • В Plant.h используйте @class GardenView
  • В GardenView.m используйте #import "Plant.h"
  • В Plant.m используйте #import "GardenView.m"

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

Причина, по которой одного @class недостаточно, состоит в том, что все, что делает @class Foo, это сообщает компилятору: «Существует класс с именем Foo», не сообщая ему вообще ничего о классе. Компилятор не знает своих методов. Он не знает своего суперкласса. Все, что он знает, это то, что если он видит токен Foo, то он представляет тип класса. Вы можете использовать это в файлах заголовков, чтобы вы могли ссылаться на класс в аргументах и ​​типах возвращаемых данных, но для того, чтобы действительно делать что-либо со значениями этого типа, вам все равно понадобится полный #import. Но вы можете без проблем поместить этот #import в файл .m.

Единственный раз, когда вам нужно #import вместо @class в заголовке, - это если вы хотите наследовать от рассматриваемого класса. Вы не можете наследовать от заранее объявленных классов, поэтому вам нужен полный #import. Конечно, вам также может понадобиться #import, если вам нужен доступ к другим типам, определенным в том же заголовке (например, структурам, перечислениям и т. Д.), Но это менее распространено в obj-c.

person Lily Ballard    schedule 10.12.2012
comment
Это сработало! Спасибо! Я думал, что все объявления import / @ class должны быть в файле заголовка, и что единственный импорт, который может быть в файле .m, - это ссылка на его собственный заголовок. Спасибо! - person J.R.; 13.12.2012
comment
@ Дженни: Нет. Все, что делает #import, это буквально копирует и вставляет содержимое указанного файла вместо строки #import (ну, он также проверяет, был ли ранее импортирован заголовок, и ничего не делает, если это так. Вот чем он отличается от #include). Вы даже можете поместить код в свой .h, если допустимо, чтобы код был включен в несколько единиц перевода (читайте: исходные файлы), хотя это довольно редко. - person Lily Ballard; 13.12.2012
comment
Единственный раз, когда вам нужно использовать #import вместо @class в заголовке, - это если вы хотите наследовать от рассматриваемого класса. Спасибо, не знал об этом. - person abc123; 02.01.2015
comment
Это действительно отличный пост. !! - person PrafulD; 08.11.2016