我试图从一个可变数组中删除和对象 - 一个遍历每一帧的数组(参见tick:方法)。
我正在
* 集合< __ NSArrayM:0xaa99cb0>在被列举时被突变。
异常。
所以我添加了@synchronized()
来阻止它被其他线程触及,但它仍然失败。
- (void)addEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
[_eventSubscribers addObject:eventSubscriber];
}
- (void)removeEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
@synchronized(_eventSubscribers) // Not working.
{
[_eventSubscribers removeObject:eventSubscriber];
}
}
- (void)tick:(ccTime)dt
{
for (id <EventSubscriber> subscriber in _eventSubscribers)
{
if ([subscriber respondsToSelector:@selector(tick:)])
{
[subscriber tick:dt];
}
}
}
答案 0 :(得分:9)
您需要在迭代时完全锁定数组的更新。将同步块添加到方法addEventSubscriber:
和removeEventSubscriber:
将不起作用,因为迭代时数组可以更改,因为迭代未同步。简而言之,这三种方法中只有一种可以同时运行。
您可以使用@synchronized
或NSLock
在迭代过程中手动锁定数组更新。
或者,您可以将GCD与串行调度队列一起使用,以确保一次只执行一个方法。这是如何工作的:
您还可以将队列存储为您正在进行此处理的类对象的属性。
// Create the queue
dispatch_queue_t myQueue = dispatch_queue_create("myQueue", NULL);
- (void)addEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
dispatch_sync(myQueue, ^{
[_eventSubscribers addObject:eventSubscriber];
});
}
- (void)removeEventSubscriber:(id <EventSubscriber>)eventSubscriber
{
dispatch_sync(myQueue, ^{
[_eventSubscribers removeObject:eventSubscriber];
});
}
- (void)tick:(ccTime)dt
{
dispatch_sync(myQueue, ^{
for (id <EventSubscriber> subscriber in _eventSubscribers)
{
if ([subscriber respondsToSelector:@selector(tick:)])
{
[subscriber tick:dt];
}
}
});
}
答案 1 :(得分:0)
您只是在从阵列中删除项目时获取锁定,而不是在枚举项目时获取锁定。该错误表明,在枚举中,您尝试删除项目,这是锁定但不是枚举所允许的。
在枚举之前简单地锁定数组可能也不起作用。相同的线程可以递归地锁定对象,但如果您的枚举和删除位于不同的线程上,那么尝试在枚举中删除会导致死锁。如果您遇到这种情况,则需要重新考虑您的模型。
答案 2 :(得分:0)
我经常遇到这个问题。除了本科OS课程之外,我没有线程处理/同步的经验,所以这就是我提出的。
每次迭代对象列表并想要删除某些内容时 - 而是将该对象添加到全局“objectsToRemove”数组中。在update方法中,从objectsToRemove中删除所有内容,然后清理数组以避免在下次更新时过度删除对象。
Cocos2D有一个CCArray,它本质上是一个带有一些附加功能的NSMutableArray,比如能够在迭代时删除一个项目。我自己没有读过代码,所以我不确定它是如何实现的,因此我不使用它。
答案 3 :(得分:-1)
你需要在这个函数中添加synchronized来。
- (void)tick:(ccTime)dt
{
@synchronized(_eventSubscribers){
for (id <EventSubscriber> subscriber in _eventSubscribers)
{
if ([subscriber respondsToSelector:@selector(tick:)])
{
[subscriber tick:dt];
}
}
}
}