在Objective-C中将基本类型的属性指定为nonatomic
是否有意义?
我想知道这两个属性之间的区别:
@property (nonatomic) BOOL myBool;
@property BOOL myBool;
答案 0 :(得分:25)
答案在技术上是肯定的它们是不同的,但实际上并非它们不是,除非你编写自己的访问者。
让我解释一下。对于对象指针属性,比如@property NSObject *foo
,如果使用合成访问器,则生成的代码中存在明显且重要的差异。这在Apple documentation中有描述,它指出如果属性是原子的,合成访问器将锁定对象(如果你没有指定nonatomic,它默认为原子)< / p>
因此对于对象属性在一个非常粗略的概述:非原子是更快但不是线程安全,原子(你不能指定它,但它的默认值)是线程安全但可能更慢。
(注意:如果您习惯使用Java,则可以考虑使用nonatomic
,而不是而不是指定synchronized
,而不是指定nonatomic
就像指定synchronized
一样。换句话说,atomic = synchronized)
但是BOOL是一个原语 - 实际上是一个C签名的char,因此访问应该是原子的,而不是像Jano的回答中提到的那样锁定对象。因此,当您合成访问者时,有两种可能性: 1:编译器是智能的,并且看到该属性是原始的并且避免锁定它,并且 2:编译器总是锁定对象的原子属性
据我所知,这在任何地方都没有记录,所以我尝试使用XCode中的Generate-&gt; Assembly选项并进行比较。答案并不是完全确定的,但足以说我几乎可以肯定答案是#1,编译器很聪明。我这样说,因为为原子对象属性生成的汇编代码与非原子对象属性有很大不同(更多):这是锁定对象的所有代码。另一方面,对于BOOL属性,只有一行不同 - 单个“mov”看起来不像它可能会有所不同。我还是想知道。有趣的是,另一个区别是BOOL的原子版本有一些额外的注释轮廓用于调试 - 因此编译器显然对它进行了不同的处理。
尽管如此,我认为它们在实际应用中是相同的。
但是它们在技术上仍然存在差异,如果你看不到实现,那么你正在阅读的其他一些库(你自己没有编写代码)可能会有很大的不同,这就是原因: atomic < / em>属性具有合同。合同说:“如果您在多个线程上访问我的值,我保证每个设置或获取操作将在任何其他线程开始之前完成”。
但是,你说,BOOL仍然是自然原子的,所以这个契约不是隐含的吗?
没有。 BOOL 变量自然是原子的,但我们谈论的是属性。 属性可能无法合成,甚至可能没有单个变量来备份它。这实际上很常见。考虑一下:
@property (getter=isEmptyThingo) BOOL emptyThingo;
...
- (BOOL)isEmptyThingo
{
Thingo *thingo = [self deriveTheThingo];
if ([thingo length] == 0) {
return YES;
}
return NO;
}
谁知道deriveTheThingo
中发生了什么!?
好吧,这有点做作,但关键是isEmptyThingo - 我们的getter看起来不是很原子,是吗?如果一个线程正在派生thingo而另一个线程调用以查找它是否为空,会发生什么。
长话短说:财产不是原子的。所以我们应该这样宣布。
因此,原始答案合格:如果你自己编写这个属性并使用@synthesize,那么它们可能是相同的,但你通常不应该对它们进行同样的处理。
根据经验,如果您不需要多线程支持 - 如果您正在使用UIViewControllers等UI代码,那么通常不需要多线程支持,那么只需将其声明为非原子。
答案 1 :(得分:8)
在x位架构(例如:32位,64位等)中,任何x或更小位的值将始终以原子方式读取或写入。这是任何理智的硬件实现的属性。
默认的原子属性意味着始终设置或获取属性值,而忽略其他线程正在执行的操作。这只是超出体系结构位数的属性的一个问题。编译器在任何其他类型上完全忽略Nonatomic。
示例:
@property struct { int d; } flag;
@property (atomic) struct { float x; float y; } point;
@property (atomic,copy) NSString *s;
struct { int d; }
已经是原子的,所以加法器不需要互斥。
struct { float x, float y}
如果不是原子的,则可能处于不一致状态。示例:设置{1,2}
和{3,4}
的两个线程可能与写入重叠,并且结构可能最终得到每个集合中的值:{1,4}
。
原子属性有助于线程安全,避免导致不一致的值或内存管理失败的竞争条件。仅此一项并不能保证线程安全,因为它不会处理其他问题,如死锁,饥饿,可见性等。
答案 2 :(得分:2)
是。 nonatomic
不是内存管理关键字,它与线程安全有关。此外,默认情况下属性是原子的(没有明确声明它们是非原子的),因此 是您列出的两个声明之间的差异。