【问题标题】:"Variable Undeclared" error when compiling to iOS Device, but not for Simulator编译到 iOS 设备时出现“变量未声明”错误,但不适用于模拟器
【发布时间】:2011-08-28 04:58:50
【问题描述】:

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

我已经尝试过:

  • 注释这行代码,但是它在另一个类中使用基类中的变量以相同的方式给我一个错误(它一次只返回一个错误),所以它似乎不是一个特定的错误在视图或控制器类中,因为错误发生在具有不同类型的其他类中,例如UIViewNSObject类型
  • 更改目标编译器配置,例如:架构(全部)、基础 sdk(全部 4.0 以上)没有改变任何东西

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

  • _vwHeader 创建一个属性并通过self._vwHeadersuper._vwHeader 访问它似乎可行,但是仅仅为了访问一个变量而必须创建一个属性并不能让我感到舒服,特别是因为我必须这样做对于我的项目中相同情况下的所有变量。
  • 更改了 C/C++ 编译器版本:使用 Apple LLVM Compiler 2.1 使编译错误消失,但在项目中使用其他库时会出现许多其他问题。因此,这不是一个确定的解决方案,但可能是问题所在的线索。

编辑:

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

编辑(2):

我的任何课程都没有任何属性,但我仍然收到错误消息。 我刚刚添加了测试 porpouses 的属性,以查看父类中的属性是否导致相同的行为,显然它没有。 也很奇怪的是,当我在变量中得到错误时,我用我的智能感知检查并发现它......

【问题讨论】:

  • 也许检查一下你的 xcode 模式发生了什么,即 BaseViewController.m 在 xcode 的目标成员面板中打勾
  • 你能发布一个完整的 Xcode 项目来重现这个错误吗?
  • @vocaro 抱歉,它发生在一个拥有大量公司财产的公司中,我不知道如何在其他人身上复制它

标签: iphone objective-c ios xcode4 compiler-errors


【解决方案1】:

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

总而言之,将您的方法调用更改为:

[self->_vwHeader setHidden:NO];

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

【讨论】:

  • 好的,现在我唯一的问题是为什么有时它会起作用?我的项目有什么导致这个错误被提出而其他人没有?
  • 以及为什么仅在为设备编译时会发生此错误?而不是模拟器......
  • 我不是 Objective-C 的超级专家,但这个答案让我完全困惑——我从未见过有人通过结构指针变量访问 ivars。你确定这是个好主意吗?
  • @Monolo 请参阅Referring to Instance Variables。当直接从接收者以外的对象访问变量时,它是必需的,否则是可选的。 self->ivar 的编译方式与 ivar 完全相同。
  • 当您使用 ivar 综合时,这实际上是 GCC 4.2(与当前 Xcode 一起分发)中的一个错误。它适用于 LLVM GCC 4.2。
【解决方案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];
}

@结束

【讨论】:

  • 我已经完成了几次清理和构建,即使在关闭并重新打开 XCode 之后也是如此。另外,我的搜索路径已经是空的了
  • 你可以尝试在它之前添加@public声明,我认为这是默认的,但可能不是出于某种原因。
  • @public、@protected 和其他修饰符也不起作用
  • 正如我在问题中指出的那样,我已经尝试创建一个属性。但这并不能解决问题,只是掩盖它,因为它发生在我的项目中“似乎可以解决问题,但不能完全为 _vwHeader 创建属性并通过 self._vwHeader 或 super._vwHeader 访问它似乎有效,但是为了访问变量而必须创建一个属性并不能让我感到舒服,特别是因为我必须为我的项目中相同情况下的所有变量都这样做。”
【解决方案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;

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

将属性的合成改为:

@implementation LocationModalController

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

神奇地解决了问题!

问候

【讨论】:

  • 但他的问题是我没有属性...如果您删除所有属性和syntesizes,访问_dataContext 是否有问题?因为这就是发生在我身上的事情:(
  • 不,当我删除合成和属性时,我能够访问 _dataContext 而没有错误——这就是我找到解决方案的原因。我建议你在课堂上寻找其他一些代码错误——也许就是这样。
  • 这不是“错误合成”; GCC 4.2 进行 ivar 合成(因此您不需要用 ivars 污染头文件),但有几个错误。第一个是您需要使用self-> 来访问基类的 ivars,第二个是 GDB 不知道它们因此无法打印它们(啊!)。
【解决方案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

【讨论】:

  • 因为它不是运行时错误,它是编译错误,它没有解决问题,错误现在发生在if(!_vwHeader)
【解决方案6】:

当您为目标和模拟进行编译时,数据成员可能是受保护的或私有的。默认情况下,目标可能是私有的,这似乎导致了问题。尝试使用 @private@protected 关键字。

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

特别是@synthesize propertyName = prefixDataNameSufix;语法,可以让你轻松调整类界面风格,而无需修改你的编码习惯。

【讨论】:

    【解决方案7】:

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

    如果您认为您的超类没问题,请查看您的子类,检查您的 iVar 和属性以及 .m 文件中的综合部分

    【讨论】:

      【解决方案8】:

      我遇到了这个确切的问题。

      就我而言,我依赖于 ivar 综合属性。也就是说,我没有声明 UITextView *textView_,但我做了 @synthesize textView = textView_;

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

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

      @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 文件中将它们声明为弱、非原子是问题所在。我以前从未遇到过这种情况,但是在从属性声明中删除(弱,非原子)之后,一切都恢复正常了。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-02-15
            • 2014-12-06
            • 1970-01-01
            • 2010-12-15
            • 1970-01-01
            相关资源
            最近更新 更多