属性声明中的atomic
和nonatomic
意味着什么?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者之间的运作区别是什么?
最后两个是相同的; “atomic” 是默认行为( 请注意,它实际上不是关键字; 仅通过缺少 nonatomic
atomic
来指定 - 在最近版本的 llvm / clang 中添加了atomic
作为关键字)。
假设你是 @synthesizing 方法实现,原子与非原子会改变生成的代码。如果您正在编写自己的 setter / getter,则 atomic / nonatomic / retain / assign / copy 仅仅是建议性的。 (注意:@synthesize 现在是最近版本的 LLVM 中的默认行为。也没有必要声明实例变量; 它们也会自动合成,并且会在其名称前加上_
以防止意外直接访问)。
对于 “原子”,合成的 setter / getter 将确保始终从 getter 返回整个值或由 setter 设置,而不管任何其他线程上的 setter 活动。也就是说,如果线程 A 位于 getter 的中间,而线程 B 调用 setter,则实际可行的值 - 一个自动释放的对象,很可能 - 将返回给 A 中的调用者。
在nonatomic
,没有这样的保证。因此, nonatomic
比 “原子” 快得多。
什么 “原子” 不就是做出关于线程安全的任何保证。如果线程 A 与线程 B 同时调用 getter 并且 C 调用具有不同值的 setter,则线程 A 可以获得返回的三个值中的任何一个 - 在调用任何 setter 之前的值或者传递给 setter 的任一值在 B 和 C 中。同样,对象可能最终得到 B 或 C 的值,无法分辨。
确保数据完整性 - 多线程编程的主要挑战之一 - 是通过其他方式实现的。
添加到此:
当多个依赖属性在起作用时,单个属性的atomicity
性也不能保证线程安全。
考虑:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
在这种情况下,线程 A 可以通过调用setFirstName:
然后调用setLastName:
来重命名对象。同时,线程 B 可以在线程 A 的两个调用之间调用fullName
,并将接收与旧的姓氏一起使用的新名字。
要解决此问题,您需要一个事务模型 。即一些其他类型的同步和 / 或排除,允许在更新依赖属性时排除对fullName
访问。
这在 Apple 的文档中有解释,但下面是实际发生的一些示例。请注意,没有 “atomic” 关键字,如果未指定 “nonatomic”,则属性为 atomic,但明确指定 “atomic” 将导致错误。
//@property(nonatomic, retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
现在,原子变体有点复杂:
//@property(retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}
- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[userName_ retain];
[userName release];
userName = userName_;
}
}
基本上,原子版本必须采取锁定以保证线程安全,并且还会碰撞对象的引用计数(以及自动释放计数以平衡它),以便保证对象存在对象,否则存在如果另一个线程正在设置该值,则是一个潜在的竞争条件,导致引用计数降至 0。
根据属性是标量值还是对象,以及如何保留,复制,只读,非原子等交互,实际上有很多不同的变体如何工作。一般来说,属性合成器只知道如何为所有组合做 “正确的事”。