Objective-C属性,它们如何工作?

时间:2011-02-10 16:35:26

标签: objective-c properties


假设我们有一个Foo类,其属性为bar 在标题中声明如下:

@interface Foo : NSObject {
    int bar;
}

@property (nonatomic, assign) int bar;

@end

在.m我当然有@synthesize bar;

现在,我的问题是,如果删除int bar;行,属性的行为方式相同,那么该行真的有必要吗?我错过了一些基本概念吗?

谢谢!

5 个答案:

答案 0 :(得分:3)

如果没有与属性同名的实例变量(ivar),现代运行时会创建一个指定属性名称的新ivar,以便在看到@synthesize时保存属性值。

如果您的属性未定义为非原子并且您希望您的代码是线程安全的,那么它可能会帮助您不引用ivar(无论您是声明它还是它已被合成),因为这将阻止您在属性时直接访问它正在改变。据我所知,没有办法获得@synthesize为原子属性获取的同一个锁,因此你不能通过其合成访问器执行原子属性的ivar的安全读取(除非你编写一个显式的setter并锁定一些东西)你自己)。 If you are interested in writing you own accessors I have a blog post on that here.

我认为对每个属性都有一个明确的ivar更常见,但这可能是因为大多数代码都旨在与遗留运行时兼容,而不是因为它本质上是一种良好的实践。

编辑:我已更正第1段,说合成的ivar具有该属性的名称;我在Apple的文档中看不到它的名字有任何讨论,所以我认为它不是用户可访问的。感谢评论者指出这一点。

答案 1 :(得分:3)

“现代”Objective-C运行时会在遇到@synthesize时自动生成ivars。

跳过它们的好处:

  • 减少代码重复。而@property给出了ivar的类型,名称和用途(属性!),所以你不会丢失任何东西。
  • 即使没有明确宣布ivar,您仍然可以直接访问ivar。 (Xcode的一个旧版本有一个可以防止这种情况的错误,但你不会使用该版本。)

有几点需要注意:

  • 32位Mac OS X上的“旧”运行时不支持此功能。(最近版本的iOS模拟器支持 。)
  • Xcode可能无法在调试器中显示自动生成的ivars。 (我相信这是一个错误。)

由于调试器问题,目前我明确地添加了所有我的ivars并将它们标记为:

@interface Foo : NSObject {
    #ifndef SYNTHESIZED_IVARS
    int ivar;
    #endif
}

@property (nonatomic, assign) int bar;

@end

我的计划是在确认调试器能够显示ivars后删除该块。 (据我所知,这已经发生了。)

答案 2 :(得分:2)

在最新的Objective-C运行时,事实证明所有的ivars(在本例中为bar)都是从@ property / @ synthesize声明动态添加到类中的,并且在类头中不需要相应的ivar声明。唯一需要注意的是,支持此功能的最新Objective-C运行时不包括对32位应用程序的支持。

来自优秀pageCocoa with Love blog解释了更多。

答案 3 :(得分:1)

如果您正在使用现代的Obj-C运行时(例如,使用Xcode 4中的LLVM编译器),编译器可以自动为您创建实例变量。在这种情况下,您不需要声明ivar。

现代运行时由iOS,iOS模拟器和64位Mac OS X支持。您无法使用现代运行时为32位OS X构建项目。

答案 4 :(得分:0)

我相信它只能在64位模式下运行。如果你尝试为32位目标构建,它将抛出异常。

Scott Stevenson对objective-c 2更改有一个很好的概述,并提到64位运行时更改here