【问题标题】:Instance variables declared in ObjC implementation file在 ObjC 实现文件中声明的实例变量
【发布时间】:2011-07-22 04:48:11
【问题描述】:

我在观看 WWDC ARC 介绍视频时,当一些 Apple 工程师谈到 Stack 示例时,我看到了一些我在 ObjC 中从未见过的东西。

以下代码用于 ARC 的堆栈示例:

@implementation Stack 
{ 
    // instance variable declared in implementation context
    NSMutableArray *_array; 
}

- (id)init 
{
   if (self = [super init])
      _array = [NSMutableArray array];
   return self;
}

- (void)push:(id)x 
{
   [_array addObject:x];
}

- (id)pop 
{
   id x = [_array lastObject];
   [_array removeLastObject];
   return x;
}

@end

请注意在 @implementation 指令之后声明的实例变量。

现在让我感到惊讶的是,实例变量实际上可以在实现文件中声明,而不是静态变量。我的问题如下:

  • 这是在适用于 iOS 5 的 SDK 中引入的一些新结构,还是这种情况已经存在很长时间了?
  • 如果实例变量不能在对象外部访问,那么在实现中声明实例变量是否是一种好习惯?这似乎比使用 @private 指令更干净。

【问题讨论】:

  • 你有一个完整的、可编译的例子吗?
  • 以上代码在 iOS 5 SDK 下应该可以正常编译。
  • 在类扩展中添加 iVar 怎么样?
  • @OscarGomez 尝试在扩展中声明 ivars 在当前版本的带有 Clang 的 Xcode 中会出现错误:“实例变量可能未放置在类扩展中”。这是以前允许的吗?
  • @Danra 我在网上查了一下,好像因为某些奇怪的原因它只能在 iOS 上运行。

标签: objective-c automatic-ref-counting


【解决方案1】:

这确实是一个新的语言特性,如果您必须声明您的 ivars(而不是简单地声明属性并让编译器为您生成 ivars),这是一个很好的做法。你的头文件理论上应该只为你的类公开公共接口;其他一切都属于实现。

需要注意的是,实现文件 ivars 对子类不可见,如果您手动生成需要子类化的 setter 和 getter,这有时会有点尴尬。

【讨论】:

  • 假设我创建了一个类“A”,它只在实现文件中声明其 ivars(用于封装),但我想创建一个可变子类“MutableA”。如何访问 A 中的实现 ivars?注意:这些 ivars 没有属性,也没有 getter/setter。
  • 一位 Apple 工程师向我介绍了这项新功能,并建议我使用它。在查看 NSAttribututedString.h 并且找不到 ivars 之前,有点忘记了它。 Objective-C 主题“定义一个类”已相应更新,并将接口中的 ivars 声明称为“历史”至于子类中的可见性 - 子类实现是否只使用访问器函数?
  • @GTAE86 是的,尽管我认为使用标头声明(或标头和实现声明的混合)仍然很常见。
  • @SeamusCampbell:上面的代码可以在 iOS4.0 中运行吗?我已经检查了 deplyoment target4.0 并且它正在工作,但在运行时它会导致任何问题吗?
  • 这与在扩展中声明 ivars(即@interface MyClass () { ... })相比如何?它还允许您不在标头中声明 ivars。
【解决方案2】:

在实现中声明 iVar 绝对是目标 C 中的一个新结构。 您需要使用 xcode4.2 并在构建设置中选择 LLVM 编译器。 这个想法是让你的头文件更干净。您可以在花括号内列出您的 ivars 像这个例子;

@implementation MyClass {    
  int var1;
  int var2;
}

Rahul 给出的答案并不真正正确,尽管您可以按照他所说的方式对变量进行 delare,编译器会将它们视为静态变量。可能对于他使用它们的情况无关紧要。

【讨论】:

【解决方案3】:

我是 Objective C 的新手,我发现在标题中声明 ivars 的做法非常奇怪。这意味着在其公共标头中声明对象的内部状态,这违背了封装的概念。

例如,假设您拥有一台 iPad。 Apple 不希望你打开 iPad 并四处撬动,弄乱里面的元素。如果他们想让你修改某些东西,iPad 会有一个设置让你改变它。

同样,我不希望其他程序员看到我的对象的 ivars。它是我对象的内部状态。如果我想让你访问内部状态,我会为它声明属性。

所以,就像在其他语言中一样,我会将我的 ivars 隐藏在实现文件中,而不是在标题中声明它们。

在标题中声明 ivars 让我觉得非常奇怪。 这些 ivars 是特定于实现的,不应该是头文件的一部分。

【讨论】:

    猜你喜欢
    • 2012-11-28
    • 1970-01-01
    • 2015-06-28
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多