2012-09-01 26 views
2

我有一个controller它拥有一个阵列actors。演员是一个将由controller调用的对象。如何安全地循环修改可变数组?

问题:controller遍历actors数组并发送给每个角色-actionMessage。演员可以使用controller创建并注册另一个演员,或者从控制器的演员阵列中删除演员或者甚至自己。它是通过两种方式进行连接:

-registerActor:(Actor*)actor; 
-unregisterActor:(Actor*)actor; 

所以当控制器遍历演员阵列,演员名单可以更改。 编辑:任何新添加的actor都必须通过循环。

解决此问题的最佳做法是什么?我应该在迭代之前创建actors数组的副本吗?

回答

7

创建一个可变数组的副本并对其进行迭代。

NSArray *loopArray = [NSArray arrayWithArray: yourActorArray]; 

或者

NSArray *loopArray = [yourActorArray copy]; 
//in this case remember to release in nonARC environment 
+2

就我而言,这是唯一真正理智的答案。替代品大多是黑客(有些人完全忽略了如果这是唯一的修改发生,你可以使用'NS [Mutable] IndexSet'去除循环后的项目)。这不是特别愉快,但它是处理这种情况最安全的方法。 – nil

+0

我更新了这个问题以反映这一点:当添加一个Actor时,循环也必须处理它。与副本我不会处理新添加的演员。那么一个Set是更好的选项,可以将变异数组中所有不在处理集合中的actor都区分开来,让循环遍历它们呢? –

-2

您应该使用正常的循环一样

for (''initializer''; ''conditional expression''; ''loop expression'') 
{ 
    // statements to be executed 
} 

不要使用快速/目标-c for循环。它可以让你编辑阵列......

2

这是我平时做...

NSMutableArray *discardedItems = [NSMutableArray array]; 
SomeObjectClass *item; 

for (item in originalArrayOfItems) { 
    if ([item shouldBeDiscarded]) 
     [discardedItems addObject:item]; 
} 

[originalArrayOfItems removeObjectsInArray:discardedItems]; 

希望这会有所帮助。

+0

看起来很聪明,但它并没有处理在迭代期间将其他元素添加到数组中的情况,并且这些元素中的每一个都必须通过该循环。 –

2

通过可变数组进行枚举的标准过程需要在逐步完成时进行更改,即复制并遍历该数组,并更改原始数组。我猜actor的NSMutableArray是属于你的控制器的属性,并且registerActor:和unregisterActor:都改变了这个数组。如果逐步浏览副本,则可以通过方法删除原始属性中的actor,而不更改副本。

NSMutableArray *actorArrayCopy = [self.actorArray copy]; 
for (id object in actorArrayCopy){ 
    //do stuff 
}   

在某些情况下,你就废快速列举,并使用标准的for循环,但是,这是有风险的位置。如果将对象插入或从数组中移除,索引将会移动(AFAIK),这意味着您可能会跳过元素或多次遍历元素。

有些人将元素存储在快速枚举中的单独数组中,并在枚举完成后立即执行所有更改,但是您使用单独的方法添加和删除元素;元素本身决定应该发生什么并通知您。这会让事情变得更加复杂,因此一个副本可能效果最好。

1

可避免这样使数组的副本:

for(int i=0; i<[array count]; i++) 
{ 
    if(condition) 
    { 
     [array removeObjectAtIndex:i]; 

     i --; 
     continue; 
    } 
} 
1

你应该使用一组而不是数组。然后您可以复制该设置,并在完成操作后,通过差异来查看发生了什么变化。