3

为什么我必须在头文件中定义两次变量?这些变量之间有什么区别?

第一个定义在这里:

@interface MyController: UIViewController
{
    NSInteger selectedIndex;
}

第二个定义在这里:

@property (nonatomic) NSInteger selectedIndex;
4

3 回答 3

6

您所看到的在早期版本的 Objective-C 中是必需的,但现在不再需要了。

在 NeXT 使用的 Objective-C 的第一个版本中,直到引入新的运行时(在 Mac OS X 上使用 Objective-C 2.0),所有实例变量都必须在其@interface. 原因是如果你对一个类进行子类化,编译器需要知道类的实例变量布局,以便它可以看到放置子类的实例变量的偏移量。

当引入属性时,综合属性必须由类结构中的实例变量“支持”。因此,您必须同时声明实例变量和属性。

以上所有都不再正确。较新的 Objective-C 在查找实例变量偏移的方式上不那么脆弱,这意味着一些变化:

  • 并非所有实例变量都需要在@interface. 它们现在可以在@implementation: 中定义,但由于可能发生冲突和其他问题而不能在类别中定义。
  • 可以根据属性定义推断和创建合成属性的实例变量。
  • 您可以以编程方式将实例变量添加到您在运行时创建的类中(仅在您将该类注册为系统可用之前)。

因此,重申一下,您只需要在旧版本的 Objective-C 语言中同时声明实例变量和综合属性。您所看到的内容是多余的,不应被视为“最佳实践”。

[资源]

于 2012-06-20T09:24:07.587 回答
4

正如其他人指出的那样,不再需要在标头中为合成属性声明支持实例变量。

不过为了更清楚一点:您看到的不是同一个变量的两个声明,而是一个变量声明和一个属性声明。

属性基本上是一组通常用于访问实例变量的方法(在本例中为selectedIndex和)。setSelectedIndex:属性和实例变量之间是有区别的。属性的 setter/getter 可以做的不仅仅是设置变量,在您的示例中,它还可以例如更新 UI 以反映所选索引的更改,或者 getter 可以从其他变量推断索引(在这种情况下,有可能是选择索引路径)等。

合成一个属性可以让您从自己实现这些方法中解放出来,并为您提供简单地设置变量的默认实现,但您也可以像任何其他方法一样实现selectedIndex和自己,在这种情况下,您可能需要实例变量本身或完全省略它setSelectedIndex:(在推断属性的情况下)。

于 2012-06-20T09:42:56.643 回答
3

在现代运行时,您不需要两次声明它们。只需使用:

在你.h

@property (nonatomic) NSInteger selectedIndex;

{} 之间的部分是 iVar 的声明。并使用您的 @property 声明 getter 和 setter。在现代运行时,如果你只使用上面的代码,你说的基本相同(你的 iVar 现在是 _selectedIndex)。

于 2012-06-20T09:21:03.130 回答