在属性声明中,原子和非原子意味着什么?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者之间的操作差异是什么?
在属性声明中,原子和非原子意味着什么?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
这三者之间的操作差异是什么?
当前回答
原子性原子(默认)
默认为Atomic:如果不键入任何内容,则属性为原子的如果您尝试从它,您将返回一个有效值。它不做任何保证关于这个值可能是什么,但你会得到好的数据,而不是只是垃圾记忆。如果您有多个线程或多个进程指向一个变量,一个线程可以读取,另一个线程可以写入。如果他们同时命中时间,读取器线程保证获得以下两个值之一:在改变之前或改变之后。什么原子没有给你任何形式的保证可能会得到。原子通常与线程安全相混淆,这是不正确的。你需要保证你的线程安全其他方式。然而,atomic将保证,如果您尝试阅读,你会得到某种价值。
非原子的
另一方面,非原子的,正如你可能猜到的,只是意味着,“不要做原子的事情。”你失去的是保证你总是要得到一些东西。如果你试着在写,你可以取回垃圾数据。但另一方面,你去快一点。因为原子财产必须发挥一些魔力为了保证你会得到一个值,它们有点慢。如果这是一个你经常访问的财产,你可能想放弃降到非原子,以确保你不会导致那样的速度处罚通道
礼貌https://academy.realm.io/posts/tmi-objective-c-property-attributes/
原子性属性属性(原子性和非原子性)没有反映在相应的Swift属性声明中,但是当从Swift访问导入的属性时,Objective-C实现的原子性保证仍然有效。
所以 — 如果你在Objective-C中定义了一个原子属性,当Swift使用它时,它仍然是原子属性。
礼貌https://medium.com/@YogevSitton/atomic-vs-非原子属性-拉什课程-d11c23f4366c
其他回答
原子意味着只有一个线程访问变量(静态类型)。原子是线程安全的,但它很慢。
非原子意味着多个线程访问变量(动态类型)。非原子线程不安全,但速度很快。
原子属性确保保留完全初始化的值,而不管有多少线程在其上执行getter和setter。
非原子属性指定合成访问器只需直接设置或返回一个值,而不保证从不同线程同时访问同一个值会发生什么。
最后两个是相同的;“atomic”是默认行为(请注意,它实际上不是一个关键字;它仅在不存在非atomic的情况下被指定——在最近版本的llvm/claung中,atomic被添加为关键字)。
假设您正在@合成方法实现,原子与非原子将更改生成的代码。如果您正在编写自己的setter/getter,原子/非原子/保留/分配/复制只是建议。(注意:@synthey现在是LLVM最新版本中的默认行为。也不需要声明实例变量;它们也会自动合成,并且在名称前加一个_,以防止意外的直接访问)。
使用“atomic”,合成的setter/getter将确保始终从getter返回或由setter设置整个值,而不管setter在任何其他线程上的活动如何。也就是说,如果线程A位于getter的中间,而线程B调用setter,则实际可行的值(很可能是自动释放的对象)将返回给A中的调用方。
在非原子中,没有这样的保证。因此,非原子比“原子”快得多。
“原子”不做的是保证线程安全。如果线程A同时调用getter,而线程B和C使用不同的值调用setter,那么线程A可能会得到返回的三个值中的任何一个值——在调用setter之前的值,或者在B和C中传递给setter的值。同样,对象可能会以B或C的值结束,这是无法分辨的。
确保数据完整性——多线程编程的主要挑战之一——是通过其他方式实现的。
添加到此:
当使用多个依赖财产时,单个属性的原子性也不能保证线程安全。
考虑:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
在这种情况下,线程A可以通过调用setFirstName:然后调用setLastName:来重命名对象。同时,线程B可以在线程A的两次调用之间调用fullName,并将接收新的名字和旧的姓氏。
要解决这个问题,您需要一个事务模型。也就是说,某些其他类型的同步和/或排除允许在更新依赖财产时排除对fullName的访问。
原子=螺纹安全
非原子=无线程安全
螺纹安全:
如果实例变量在从多个线程访问时行为正确,则它们是线程安全的,而不考虑运行时环境对这些线程执行的调度或交织,并且调用代码部分没有额外的同步或其他协调。
在我们的背景下:
如果一个线程更改了实例的值,则所有线程都可以使用更改的值,并且一次只有一个线程可以更改该值。
在何处使用原子:
如果要在多线程环境中访问实例变量。
原子的含义:
没有非原子的速度快,因为非原子的运行时不需要任何看门狗的工作。
在何处使用非原子:
如果实例变量不会被多个线程更改,您可以使用它。它可以提高性能。
苹果的文档中对此进行了解释,但下面是一些实际发生情况的示例。
请注意,没有“atomic”关键字,如果不指定“nonatomic(非原子)”,则属性是原子的,但显式指定“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。
实际上,根据财产是标量值还是对象,以及保留、复制、只读、非原子等交互方式,这些东西的工作方式有很多不同的变体。一般来说,属性合成器只知道如何为所有组合做“正确的事情”。