1

我正在尝试从一个可变数组中删除和对象 - 一个遍历每一帧的数组(参见刻度:方法)。

我正进入(状态

*集合 <__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];
       }
   }
}
4

4 回答 4

9

您需要在迭代时完全锁定对数组的更新。将同步块添加到这两种方法addEventSubscriber:并且removeEventSubscriber:将不起作用,因为由于迭代不同步,数组在被迭代时可能会发生变化。简而言之,一次只能运行这三种方法中的一种。

您可以使用@synchronized, 或 anNSLock在迭代时手动锁定数组更新。

或者,您可以将 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];
           }
       }
    });
}
于 2012-12-03T02:32:21.417 回答
0

您仅在从数组中删除项目时获得锁,而不是在枚举项目时。该错误表明在枚举中您试图删除一个项目,这是您的锁定允许但枚举不允许的。

在枚举之前简单地锁定数组也可能不起作用。同一个线程可以递归地锁定对象,但是如果您的枚举和删除在不同的线程上,那么尝试在枚举中删除将导致死锁。如果您处于这种情况,您将需要重新考虑您的模型。

于 2012-12-03T02:15:15.183 回答
0

我经常遇到这个问题。除了本科操作系统课程之外,我没有线程处理/同步的经验,所以这就是我想出的。

每次您遍历对象列表并想要删除某些东西时 - 而是将该对象添加到全局“objectsToRemove”数组中。在您的更新方法中,从 objectsToRemove 中删除所有内容,然后清理数组以避免在下一次更新时过度删除对象。

Cocos2D has a CCArray which is essentially an NSMutableArray with some added functionality– like being able to remove an item while iterating. I haven't read through the code myself, so I'm not sure how it is implemented and therefore I don't use it.

于 2012-12-10T03:38:03.267 回答
-1

您也需要在此功能中添加同步。

- (void)tick:(ccTime)dt
{
  @synchronized(_eventSubscribers){
 for (id <EventSubscriber> subscriber in _eventSubscribers)
 {
   if ([subscriber respondsToSelector:@selector(tick:)])
   {
       [subscriber tick:dt];
   }
 }
 }
}
于 2012-12-03T02:10:25.010 回答