Ошибка «Переменная необъявленная» при компиляции на устройство iOS, но не для симулятора - PullRequest
11 голосов
/ 18 мая 2011

У меня есть пользовательский 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 типы
  • Изменение конфигурации целевого компилятора, например: архитектуры (всеem), базовый sdk (все выше 4.0) ничего не изменил

Что, похоже, решает проблему, но не полностью

  • Создание свойства для _vwHeaderи доступ к нему с помощью self._vwHeader или super._vwHeader, кажется, работает, но необходимость создавать свойство просто для доступа к переменной не делает меня удобным, особенно потому, что мне пришлось бы делать это для всех переменных в той же ситуации в моем проекте.
  • изменена версия компилятора C / C ++: использование Apple LLVM Compiler 2.1 устраняет ошибку компиляции, но создает множество других проблем с другими библиотеками, используемыми в проекте.Таким образом, это не окончательное решение, но может быть ключом к пониманию проблемы.

РЕДАКТИРОВАТЬ:

Я пытался создать другую переменную, которая не являетсяуказатель, BOOL вместо UIView *, а затем использовал его в унаследованном классе: проблема также возникает

EDIT (2):

У меня нет свойств вообще ни в одном измои занятия и я все еще получаю ошибку.Я просто добавил свойства для тестовых компонентов, чтобы посмотреть, не вызвало ли свойство родительского класса такое же поведение, и, очевидно, это не так.Также странно то, что когда я получаю ошибку в переменной, я проверяю ее с помощью intellisense, и он находит ее ...

Ответы [ 10 ]

8 голосов
/ 19 мая 2011

Для ссылки на переменную экземпляра в любом объекте, кроме self, включая super, необходимо использовать оператор указателя структуры (->).Область по умолчанию переменной экземпляра защищена, что означает, что к ней можно получить доступ только в пределах класса, в котором она определена, или подкласса этого класса.Поскольку CustomViewController является подклассом BaseViewController, этой области достаточно для доступа к переменной с использованием self->_vwHeader, но если второй класс, из которого вы пытались это сделать, не является подклассом, вам также необходимо изменить область действия на@public или @package.

В итоге измените вызов метода на:

[self->_vwHeader setHidden:NO];

, и он должен работать для любых подклассов контроллера базового представления.

2 голосов
/ 15 июня 2011

Я столкнулся с такой же проблемой, как и вы. В моем случае причина была (как ни странно!) В неправильном синтезе свойств в подклассе.

Пример:

В файле .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;

ВОЛШЕБНО РЕШАЕТ ПРОБЛЕМУ!

Привет

2 голосов
/ 18 мая 2011

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

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];
}

@ конец

1 голос
/ 29 июля 2011

Возможно, что когда вы компилируете для цели и для симуляции, элементы данных являются либо защищенными, либо частными. Вероятно, для цели являются частными по умолчанию, и это, кажется, вызывает проблему Попробуйте поиграть с ключевыми словами @private и @protected.

Однако я настоятельно рекомендую вам использовать свойства даже между вашими супер / подклассами. Наличие сложной структуры немного сложно отладить. Установка свойства передаст доступ к данным через методы получения / установки (точка останова на @synthesize также работает), и вы сможете увидеть в стеке вызовов, кто к чему имеет доступ.

В частности, синтаксис @synthesize propertyName = prefixDataNameSufix; позволяет легко настраивать стиль интерфейса вашего класса без необходимости изменять привычки кодирования.

1 голос
/ 28 июля 2011

Ошибка говорит о том, что _vwHeader не объявлен.Поэтому попробуйте изменить код в:

CustomViewController.m

    #import "CustomViewController.h"
    @implementation CustomViewController

    - (void)loadView
    {
        [super loadView];
        if(!_vwHeader)
        {
           _vwHeader = [[UIView alloc]init];
        }
        [_vwHeader setHidden:NO];
    }

    @end
1 голос
/ 27 июля 2011

Я просто наткнулся на объявление вашего метода

-(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, правильно созданную.

0 голосов
/ 10 октября 2016

Если у кого-то возникла эта проблема после обновления его инструментов и устройств до iOS10, я обнаружил, что проблема была в том, чтобы объявить их слабыми, неатомными в файле .h. Я никогда не сталкивался с этим, когда делал это раньше, но после удаления (слабого, неатомного) из объявления свойства все снова заработало нормально.

0 голосов
/ 17 января 2012

См. Ответ из тк выше.Это ошибка в компиляторе, поставляемом с SDK 4.2.В частности, я видел ту же ошибку, и если на той же машине у меня установлены SDK 4.2 и SDK 4.3, ошибка исчезает (даже если я скомпилирую для 4.2).

0 голосов
/ 15 сентября 2011

У меня была именно эта проблема.

В моем случае я полагался на синтез свойства ивара.То есть я НЕ объявлял UITextView * textView_ , но я @ synthesize textView = textView _;

Это прекрасно работает на моем симуляторе iOS.Тем не менее, сборка моего устройства iOS завершается неудачно, независимо от того, использую ли я llvm или gcc.

Когда я добавляю объявление обратно в мой интерфейс:

@interface MyTableViewController : BaseTableViewController {
    @private
    UITextView *textView_; // this line is important!
}

Все работает отлично!

0 голосов
/ 11 августа 2011

У меня была точно такая же проблема, и оказалось, что я не удалил неиспользуемое свойство iVar / в SUBCLASS. Давайте назовем это session. Я удалил _session из iVar, но забыл удалить его из свойств, затем в файле .m у меня было это synthesize session = _session. После того, как я удалил их все, я могу без проблем скомпилировать устройство на iOS.

Если вы считаете, что с вашим суперклассом все в порядке, загляните в ваш подкласс, проверьте свои iVars и свойства и синтезируйте раздел в файле .m

...