我有一个属性对象:
@interface Car
@property(strong) NSLicensePlate *licensePlate;
@end
我在方法中使用该属性:
- (void) doSomething {
[_licensePlate frobnicate];
}
可以用另一种方法改变属性值:
- (void) doSomethingElse {
[self setLicensePlate:[_licensePlateDealer cleanLicensePlate]];
}
现在,如果在我使用实例变量访问牌照属性时从另一个线程调用-doSomethingElse
方法(如-doSomething
方法中所示),是否可以获得段错误?
-setLicensePlate
setter是否有可能在我调用_licensePlate
之前和分配新的有效值之前释放-frobnicate
中存储的值?是否有助于致电[self licensePlate]
而不是直接使用_licensePlate
?
答案 0 :(得分:3)
如果您想要享受此属性的atomic
行为(因为您未指定nonatomic
限定符而获得的默认行为),则必须使用getter({{ 1}}或self.licensePlate
),不要使用ivar([self licensePlate]
)。
一般来说,除了(a)_licensePlate
方法之外,在任何地方使用getter和setter通常都是谨慎的。 (b)和自定义存取方法。开销可以忽略不计,你可以避免一些潜在问题,包括原子性,内存语义,KVO,面向未来的代码,如果你在将来某个日期定制访问器方法等等。
但是,假设您只通过访问器方法(getter和setter)访问您的属性,Programming with Objective-C: Encapsulating Data描述的init
限定符确保您正在检索的指针本身/设置不会被另一个线程破坏:
[Atomic]意味着合成访问器确保始终通过getter方法完全检索值或通过setter方法完全设置,即使从不同的线程同时调用访问器也是如此。
在回答您的问题时,如果另一个线程更改atomic
属性,而licensePlate
方法在另一个线程上运行,则该方法返回之前不会释放该原始对象。 / p>
但要明确的是,frobnicate
限定符不确保线程安全。正如上面的指南继续警告我们:
注意:属性原子性与对象的线程安全性不是同义词。
考虑一个
atomic
对象,其中使用来自一个线程的原子访问器来更改一个人的名字和姓氏。如果另一个线程同时访问这两个名称,则原子getter方法将返回完整的字符串(不会崩溃),但不能保证这些值将是相对于彼此的正确名称。如果在更改之前访问了第一个名称,但在更改后访问了姓氏,则最终会出现一组不一致,不匹配的名称。这个例子非常简单,但是当在相关对象的网络中考虑时,线程安全问题变得更加复杂。 Concurrency Programming Guide中详细介绍了线程安全性。
因此,可能在一个线程上使用XYZPerson
同时在另一个线程上执行其他操作时是线程安全的,但它也可能不是。这取决于使用此牌照对象可以完成的所有不同事情。由于frobnicate
提供的保护是如此简约,我们经常会采用一些同步(通过GCD串行队列或GCD读写器模式,或通过Threading Programming Guide: Synchronization中概述的任何同步方法,如锁)协调来自不同线程的交互。
答案 1 :(得分:0)
定义属性时,可以将其设置为atomic
(默认值)或nonatomic
。
由于您使用的是atomic
默认设置,因此您应该对线程安全做得很好,但这也取决于您实施frobnicate
,setLicensePlate:
和{{1}的方式}。
请参阅此问题以获取有关cleanLicensePlate
与atomic
的更多详细信息:What's the difference between the atomic and nonatomic attributes?