Ошибка "Variable Undeclared" при компиляции на iOS-устройстве, но не для Simulator
У меня есть пользовательский UIVIewController, который является базовым классом для других контроллеров и имеет экземпляр пользовательской переменной UIView, к которой обращаются наследуемые классы.
BaseViewController.h
@interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
@end
BaseViewController.m
#import "BaseViewController.h"
@implementation BaseViewController
-(void)loadView {
[super loadView];
_vwHeader = [[UIView alloc] init];
}
@end
CustomViewController.h
#import "BaseViewController.h"
@interface CustomViewController : BaseViewController
@end
CustomViewController.m
#import "CustomViewController.h"
@implementation CustomViewController
- (void)loadView
{
[super loadView];
[_vwHeader setHidden:NO];
}
@end
Проблема в том, что когда я запускаю его на симуляторе, все работает отлично, но когда я перехожу на устройство, у меня есть ошибка в строке [_vwHeader setHidden:NO];
, которая гласит: '_vwHeader' undeclared (first use in this function)
Я уже пытался:
- Комментировать эту строку кода, но затем она дает мне ошибку в другом классе, используя переменную из базового класса одинаково (она возвращает только одну ошибку за раз), поэтому кажется, что это не особая ошибка в представлении или классе контроллера, поскольку ошибка возникает в других кланах с разными типами, таких как
UIView
и NSObject
types
- Изменить конфигурацию целевого компилятора, такую как: архитектуры (все они), базовый sdk (все выше 4.0) ничего не изменили
Что, похоже, решает проблему, но не полностью
- Создание свойства для
_vwHeader
и доступ к нему с помощью self._vwHeader
или super._vwHeader
, похоже, сработает, но необходимость создания свойства только для доступа к переменной не делает меня удобной, особенно потому, что мне нужно будет это сделать для всех переменных в той же ситуации внутри моего проекта.
- изменена версия компилятора C/С++: использование
Apple LLVM Compiler 2.1
делает ошибку компиляции упущенной, но дает множество других проблем с другими библиотеками, которые используются в проекте. Таким образом, это не окончательное решение, но может быть ключом к проблеме.
ИЗМЕНИТЬ:
Я попытался создать еще одну переменную, которая не является указателем, BOOL
вместо UIView *
, а затем использовала ее в унаследованном классе: проблема также возникает
ИЗМЕНИТЬ (2):
У меня нет свойств вообще ни в одном из моих классов, и я до сих пор получаю ошибку.
Я просто добавил свойства тестовых porpouses, чтобы увидеть, вызвало ли свойство в родительском классе такое же поведение, и, по-видимому, это не так.
Что-то странное и в том, что когда я получаю ошибку в переменной, я проверил ее с intellisense и нашел ее...
Ответы
Ответ 1
Чтобы ссылаться на переменную экземпляра в любом объекте, отличном от self
, включая super
, вы должны использовать оператор указателя структуры (->
). Область по умолчанию для переменной экземпляра защищена, что означает, что ее можно получить только в пределах класса, в котором он определен, или подкласса этого класса. Поскольку CustomViewController
является подклассом BaseViewController
, этой области достаточно для доступа к переменной с помощью self->_vwHeader
, но если второй класс, из которого вы пытались сделать это, не является подклассом, вам также необходимо будет изменить область действия либо @public
или @package
.
В итоге измените вызов метода на:
[self->_vwHeader setHidden:NO];
и он должен работать для любых подклассов контроллера базового представления.
Ответ 2
Сделайте чистую и сборку, а также убедитесь, что вы не указали определенный путь поиска каркаса в настройках сборки. Если вы оставите его пустым, вы должны получить правильные библиотеки.
ну я не знаю, должен работать.
BaseViewController.h
@interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
@property(nonatomic,retain)UIView *_vwHeader;
@end
BaseViewController.m
@synthesize _vwHeader;
CustomViewController.m
#import "CustomViewController.h"
@implementation CustomViewController
- (void)loadView
{
[super loadView];
[self._vwHeader setHidden:NO];
}
@end
Ответ 3
Я столкнулся с такой же проблемой, как и вы. В моем случае причиной была (странно!) Неправильная синтезация свойств в подклассе.
Пример:
В .h файле подкласса вы имеете следующее объявление
BOOL _flag;
...
@property (nonatomic, assign) BOOL flag;
в то время как вы синтезируете свойство не так:
@synthesize flag;
вместо
@synthesize flag = _flag;
Странно, что компилятор не жалуется на неправильную синтезацию (свойства даже работают отлично!), но вызывает ошибку, когда я пытаюсь получить доступ к защищенным полям, объявленным в базовом классе.
Подробное объяснение
Вот как выглядит мой код
У меня есть базовый класс (выдержка):
@interface BaseEditionModalController : NSObject
{
DataContext *_dataContext;
}
И у меня есть подкласс (выдержка):
@interface LocationModalController : BaseEditionModalController
{
MCLocation *_readLocation;
LocationCommModel *_oldLocationCommModel;
}
//This is MCLocation for reading only - from the main application context
@property (nonatomic, retain) MCLocation *readLocation;
@property (nonatomic, retain) LocationCommModel *oldLocationCommModel;
@end
И в LocationModalController.m У меня есть следующие неправильные объявления:
@implementation LocationModalController
@synthesize readLocation;
@synthesize oldLocationCommModel;
Пытаясь получить доступ к _dataContext в LocationModalController, выдается сообщение о том, что _dataContext не объявлен.
Изменение синтеза свойств на:
@implementation LocationModalController
@synthesize readLocation = _readLocation;
@synthesize oldLocationCommModel = _oldLocationCommModel;
ВОЛШЕБНО РЕШАЕТ ПРОБЛЕМУ!
Привет
Ответ 4
Я просто натыкаюсь на объявление вашего метода
-(void)loadView { ... }
В представлении первая точка, на которую вы можете положиться, что все полностью инициализировано, вызвано после - (void) viewDidLoad. Возможно, ваш код работает на симуляторе, потому что ваш Mac достаточно быстр, чтобы справиться с этой проблемой скорости, но ваше мобильное устройство не работает.
Возможно, попробуйте следующее кодирование:
Ваш файл BaseViewController.h:
@interface BaseViewController : UIViewController {
UIView *_vwHeader;
}
@end
Ваш файл BaseViewController.m:
#import "BaseViewController.h"
@implementation BaseViewController
-(void)viewDidLoad {
[super viewDidLoad];
_vwHeader = [[UIView alloc] init];
}
Ваш файл CustomViewController.h:
@interface CustomViewController : BaseViewController {
}
@end
Ваш файл CustomViewController.m:
#import "CustomViewController.h"
-(void)viewDidLoad {
[super viewDidLoad];
[_vwHeader setHidden:NO];
}
Теперь ваш CustomViewController может полагаться на каждую переменную экземпляра в BaseViewController, которая была правильно создана.
Ответ 5
Ошибка говорит о том, что _vwHeader не объявлен.
Поэтому попробуйте изменить код в:
CustomViewController.m
#import "CustomViewController.h"
@implementation CustomViewController
- (void)loadView
{
[super loadView];
if(!_vwHeader)
{
_vwHeader = [[UIView alloc]init];
}
[_vwHeader setHidden:NO];
}
@end
Ответ 6
Возможно, что при компиляции для целей и для моделирования члены данных либо защищены, либо приватны. Вероятно, для цели закрыты по умолчанию, и это, похоже, вызывает проблему. Попробуйте сыграть с ключевыми словами @private
и @protected
.
Однако я настоятельно рекомендую использовать свойства даже между супер/подклассами. Сложная структура немного сложна для отладки. Настройка свойства передаст доступ к данным через методы getter/setter (также будет работать точка останова на @synthesize
), и вы сможете увидеть в стеке вызовов, который обращается к чему.
В частности, синтаксис @synthesize propertyName = prefixDataNameSufix;
позволяет вам легко настраивать стиль интерфейса класса, не изменяя привычки кодирования.
Ответ 7
У меня была такая же проблема, и оказалось, что я не удалял неиспользуемое свойство iVar/в SUBCLASS. Позвольте называть его session
. Я удалил _session
из iVar, но я забыл удалить его из свойств, а затем в .m файле у меня был этот synthesize session = _session
. Как только я удалю их все, я могу скомпилировать для iOS-устройства без проблем.
Если вы считаете, что ваш суперкласс отлично, загляните в свой подкласс, проверьте свой iVars и свойства и раздел синтеза в файле .m
Ответ 8
У меня была эта точная проблема.
В моем случае я полагался на синтез ivar свойства. То есть я НЕ объявлял UITextView * textView _, но я сделал @synthesize textView = textView _;
Это отлично работает на моем iOS-симуляторе. Однако мое устройство iOS не работает, независимо от того, использую ли я lvvm или gcc.
Когда я добавляю объявление обратно в мой интерфейс:
@interface MyTableViewController : BaseTableViewController {
@private
UITextView *textView_; // this line is important!
}
Все работает отлично!
Ответ 9
См. ответ от tc выше. Это ошибка в компиляторе, поставляемом с sdk 4.2.
В частности, я видел ту же ошибку, и если на том же компьютере у меня установлены sdk 4.2 и sdk 4.3, ошибка исчезает (даже если я компилирую для 4.2).
Ответ 10
Если у кого-то возникла эта проблема после обновления своих инструментов и устройств до iOS10, у меня было это и было обнаружено, что объявление их как слабых, неатомных в файле .h было проблемой. Я никогда не сталкивался с этим, когда делал это раньше, но после удаления (слабой, неатомической) из объявления свойств все снова работало нормально.