问题 编译到iOS设备时出现“可变未声明”错误,但不适用于模拟器


我有一个自定义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)

我已经尝试过:

  • 注释这行代码,但是它在另一个类中使用基类中的变量以相同的方式给出了一个错误(它一次只返回一个错误),所以看起来它不是视图中的特定错误或者控制器类,因为错误发生在具有不同类型的其他clases中,例如 UIView 和 NSObject 类型
  • 更改目标编译器配置,例如:架构(所有这些),基本sdk(都高于4.0)没有改变任何东西

什么似乎解决了这个问题,但并不完全

  • 为...创建属性 _vwHeader 并通过访问它 self._vwHeader 要么 super._vwHeader 似乎工作,但必须创建一个属性只是为了访问变量不会让我很舒服,特别是因为我必须在我的项目内的相同情况下为所有变量做这件事。
  • 改变了C / C ++编译器版本:使用 Apple LLVM Compiler 2.1 使编译错误消失,但在项目中使用的其他库给出了一堆其他问题。因此,它不是一个明确的解决方案,但可能是问题所在的线索。

编辑:

我试图创建另一个不是指针的变量,a BOOL 而不是 UIView *  然后在继承的类中使用它:问题也会发生

编辑(2):

我的任何课程都没有任何属性,但我仍然得到错误。 我刚刚添加了测试porpouses的属性,以查看父类中的属性是否导致相同的行为,显然它没有。 一些奇怪的事情是,当我在变量中得到错误时,我检查了我的intellisense它发现它...


2423
2018-05-18 16:06


起源

也许检查你的xcode架构正在发生的事情,即在xcode的目标成员资格面板中勾选BaseViewController.m - railwayparade
你能发布一个重现这个错误的完整Xcode项目吗? - vocaro
@vocaro对不起,它发生在一个有很多公司财产的地方,我不知道如何在其他公司重现它 - Felipe Sabino


答案:


为了引用除了之外的任何对象中的实例变量 self, 包含 super,你必须使用结构指针运算符(->)。实例变量的默认范围是受保护的,这意味着它只能在其定义的类或该类的子类中访问。以来 CustomViewController 是。的子类 BaseViewController,此范围足以使用访问变量 self->_vwHeader,但如果您尝试执行此操作的第二个类不是子类,则还需要将范围更改为 @public 要么 @package

总之,将方法调用更改为:

[self->_vwHeader setHidden:NO];

它应该适用于基本视图控制器的任何子类。


8
2018-05-19 04:04



这不是必要的。 - Grady Player
好的,现在我唯一的问题是为什么有时它会起作用?我的项目有什么能够引发其他人没有的错误? - Felipe Sabino
我不是Objective-C的超级专家,但这个答案让我感到困惑 - 我从未见过有人通过结构指针变量访问ivars。你确定这是个好主意吗? - Monolo
@Monolo见 参考实例变量。直接从接收器以外的对象访问变量时需要它,否则是可选的。 self->ivar 编译完全相同 ivar。 - ughoavgfhw
当你使用ivar合成时,这实际上是GCC 4.2中的一个错误(与当前的Xcode一起分发)。它适用于LLVM GCC 4.2。 - tc.


做一个干净的构建,并确保您没有在构建设置中指定特定的框架搜索路径。如果你把它留空,你应该得到正确的库。 我不知道,应该工作。

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

@结束


2
2018-05-18 18:33



即使在关闭并重新打开XCode之后,我已经做了几次清理和构建。此外,我的搜索路径已经是空的 - Felipe Sabino
您是否尝试过更改ios部署目标? - Grady Player
是的,我测试了4.0以上的所有 - Felipe Sabino
你可以尝试在它之前添加@public声明,我认为这是默认的,但可能不是出于某种原因。 - Grady Player
@ public,@ protected和其他修饰符也不起作用 - Felipe Sabino


我遇到了和你一样的问题。在我的情况下,原因是(奇怪的是)在子类中错误地合成属性。

例:

在子类的.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;

试图访问LocationModalController中的_dataContext会产生_dataContext未声明的错误。

将属性的合成更改为:

@implementation LocationModalController

@synthesize readLocation = _readLocation;
@synthesize oldLocationCommModel = _oldLocationCommModel;

神奇地解决了问题!

问候


2
2018-06-15 14:24



但他的问题是我没有属性......你有没有问题访问 _dataContext 如果你删除所有属性和 syntesizeS'因为那是发生在我身上的事情:( - Felipe Sabino
不,当我删除了合成和属性时,我能够无错误地访问_dataContext - 这就是我找到解决方案的原因。我建议你在课堂上寻找其他一些代码错误 - 也许就是这种情况。 - manicaesar
这不是一个“错误的合成”; GCC 4.2进行了ivar合成(所以你不需要用ivars污染头文件)但有一些bug。首先是你需要使用 self-> 访问基类的ivars,第二个是GDB不知道它们所以不能打印它们(argh!)。 - tc.


我只是偶然发现你的方法声明

-(void)loadView { ... }

在视图中,您可以依赖于所有内容都已完全初始化的第一点是在调用viewDidLoad之后 - (void)。也许你的代码可以在模拟器上运行,因为你的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中的每个实例变量来正确实例化。


1
2017-07-27 16:10



抱歉,但我没有说“它在模拟器上运行而不在设备中”,我说它根本没有为设备编译 - Felipe Sabino


该错误表明_vwHeader未声明。 因此,请尝试修改以下代码:

CustomViewController.m

    #import "CustomViewController.h"
    @implementation CustomViewController

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

    @end

1
2017-07-28 04:42



因为它不是一个运行时错误,它是一个编译器,它没有解决问题,现在正在发生错误 if(!_vwHeader) 线 - Felipe Sabino


编译目标和模拟时,数据成员可能是受保护的,也可能是私有的。默认情况下,目标可能是私有的,这似乎会导致问题。尝试玩 @private 和 @protected 关键字。

但是,我强烈建议您甚至在超级/子类之间使用属性。具有复杂的结构有点难以调试。设置属性将通过getter / setter方法(断点)传输对数据的访问 @synthesize 也工作)你将能够在调用堆栈中看到谁正在访问什么。

特别是语法 @synthesize propertyName = prefixDataNameSufix; 允许您轻松调整类界面风格,而无需修改编码习惯。


1
2017-07-29 08:05





我有完全相同的问题,事实证明我没有删除SUBCLASS中未使用的iVar /属性。我们称之为 session。我删除了 _session 从iVar但我忘了从属性中删除它,然后在.m文件中我有这个 synthesize session = _session。一旦我将它们全部删除,我就可以毫无问题地为iOS设备编译。

如果您认为您的超类很好,请查看您的子类,检查您的iVars和属性并合成.m文件中的部分


0
2017-08-11 03:32





我遇到了这个问题。

在我的情况下,我依靠ivar合成一个属性。也就是说,我没有声明 UITextView * textView_,但我做到了 @synthesize textView = textView_;

这在我的iOS模拟器上构建得很好。但是,无论我使用llvm还是gcc,我的iOS设备构建都会失败。

当我将声明添加回我的界面时:

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

一切正常!


0
2017-09-15 08:54





请参阅上面的tc的答案。这是sdk 4.2附带的编译器中的一个错误。 具体来说,我已经看到了相同的错误,如果在同一台机器上我安装了sdk 4.2和sdk 4.3错误消失了(即使我编译为4.2)。


0
2018-01-17 10:12





如果在将他们的工具和设备升级到iOS10之后有人遇到这个问题,我就有了它,发现在.h文件中声明它们是弱的,非原子的是问题。我之前从未遇到过这种情况,但是在从属性声明中删除(弱,非原子)之后,一切都运行良好。


0
2017-10-10 14:16