Objective c NSArray的线程安全枚举

Objective c NSArray的线程安全枚举,objective-c,thread-safety,nsarray,grand-central-dispatch,Objective C,Thread Safety,Nsarray,Grand Central Dispatch,以下是线程安全的吗 @property (nonatomic, copy) NSArray *objects; … dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^ { for (MyClass *current in weakSelf.objects) { current.property = 0.0; } }); 特别是当我在后台线程中枚举时,s

以下是线程安全的吗

@property (nonatomic, copy) NSArray *objects;
…
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^
{
    for (MyClass *current in weakSelf.objects) {
       current.property = 0.0;
    }
});
特别是当我在后台线程中枚举时,
self.object
被设置为不同的NSArray时,我不能确切地确定会发生什么

它是否继续枚举旧的NSArray


只要我正在枚举NSArray(而不是NSMutableArray),我就不需要@syncronize right?

快速枚举检测正在枚举的集合是否更改,请参见例如。此外,如果一个块是异步执行的,它会保留对
self
的引用,引自:“……从编译器的角度来看,传递给
dispatch\u async
的块会保留对
self
的引用”。

我认为其结果是,当您更改指向集合的指针时,异步执行的快速枚举将引发异常。

快速枚举检测正在枚举的集合是否更改,请参见例如。此外,如果一个块是异步执行的,它会保留对
self
的引用,引自:“……从编译器的角度来看,传递给
dispatch\u async
的块会保留对
self
的引用”。

我认为其结果是,当您更改指向集合的指针时,异步执行的快速枚举将引发异常。

这不是线程安全的

首先,这个性质是非原子的。因此,无法保证当该线程仍在getter方法中时,在其指针被放入适当的寄存器和时间控件返回调用代码之间,该数组还没有被另一个线程释放(因此可能被解除分配)。也就是说,从这个线程的角度来看,该方法可能返回一个无效的悬空指针

即使在您输入
for
循环时指针仍然有效,快速枚举也可能需要多次向数组发送消息。尽管
-objects
getter只会被调用一次,但我认为您不能确定ARC是否会为您保留返回的数组(假设您使用的是ARC)。如果另一个线程将属性设置为引用不同的数组,则setter将释放旧数组。如果这是最后一个引用,那么数组可能会被释放(这将释放所有包含的对象)。正在进行的枚举可能会引用解除分配的对象

使用
@synchronized(self)
在块的内部以及setter(或任何调用setter的东西)中进行操作就足以确保安全。但是,由于您已经将该块调度到队列中,因此应该考虑使用自定义队列而不是<代码> @同步()/<代码>来协调属性上的操作。队列应该是串行的,也可以是并发的,您必须为所有写操作使用屏障任务


或者,我认为将属性设置为原子就足够了。文档中说,原子属性的getter将执行诸如获取锁、将实例变量复制到临时变量、保留并自动释放它、释放锁以及返回临时变量值之类的操作。

这不是线程安全的

首先,这个性质是非原子的。因此,无法保证当该线程仍在getter方法中时,在其指针被放入适当的寄存器和时间控件返回调用代码之间,该数组还没有被另一个线程释放(因此可能被解除分配)。也就是说,从这个线程的角度来看,该方法可能返回一个无效的悬空指针

即使在您输入
for
循环时指针仍然有效,快速枚举也可能需要多次向数组发送消息。尽管
-objects
getter只会被调用一次,但我认为您不能确定ARC是否会为您保留返回的数组(假设您使用的是ARC)。如果另一个线程将属性设置为引用不同的数组,则setter将释放旧数组。如果这是最后一个引用,那么数组可能会被释放(这将释放所有包含的对象)。正在进行的枚举可能会引用解除分配的对象

使用
@synchronized(self)
在块的内部以及setter(或任何调用setter的东西)中进行操作就足以确保安全。但是,由于您已经将该块调度到队列中,因此应该考虑使用自定义队列而不是<代码> @同步()/<代码>来协调属性上的操作。队列应该是串行的,也可以是并发的,您必须为所有写操作使用屏障任务


或者,我认为将属性设置为原子就足够了。文档中说,原子属性的getter将执行诸如获取锁、将实例变量复制到临时变量、保留并自动释放它、释放锁以及返回临时变量的值之类的操作。

他并不是在询问如何修改数组。数组是不可变的。他询问如何设置
对象
属性以引用不同的不可变数组。另外,他使用了对self的弱引用(
weakSelf
)。从引用的引用中,我感觉更改指向集合的指针与更改集合本身具有相同的效果。此外,文档还说,该块保留了对self的引用,并使用该引用访问属性。快速枚举客户端代码(编译器为
for
循环生成的代码)无法知道某个对象的
objects
属性已更改。它在
NSArray
指针上运行。一旦在一开始就获得了,它就不再关心这个