Ошибка "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 было проблемой. Я никогда не сталкивался с этим, когда делал это раньше, но после удаления (слабой, неатомической) из объявления свойств все снова работало нормально.