2

我有controller一个数组,其中包含actors. Actor 是一个对象,它将被controller.

问题:controller遍历actors数组并向每个参与者发送一个-actionMessage. Actor 可以使用 来创建和注册另一个 Actor controller,或者从控制器的 Actor 数组中删除一个 Actor 甚至它自己。它通过两种方法路由:

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

因此,当控制器迭代演员数组时,演员列表可以改变。编辑:任何新添加的演员也必须通过循环。

处理这个问题的最佳实践是什么?我应该在迭代之前创建演员数组的副本吗?

4

6 回答 6

6

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

NSArray *loopArray = [NSArray arrayWithArray: yourActorArray];

或者

NSArray *loopArray = [yourActorArray copy];
//in this case remember to release in nonARC environment
于 2012-09-01T19:40:38.890 回答
2

这是我平时做的...

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

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

[originalArrayOfItems removeObjectsInArray:discardedItems];

希望这会有所帮助。

于 2012-09-01T19:47:21.883 回答
2

枚举一个可变数组的标准过程需要在您逐步完成时进行更改,即制作一个副本并对其进行迭代,从而更改原始数组。我猜演员的 NSMutableArray 是属于您的控制器的属性,并且 registerActor: 和 unregisterActor: 都改变了这个数组。如果您单步执行副本,则可以通过方法从原始属性中删除演员,而无需更改副本。

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

在某些情况下,您可以放弃快速枚举并使用标准 for 循环,但是,这在这里是有风险的。如果从数组中插入或删除对象,则索引将移动(AFAIK),这意味着您最终可能会跳过元素或多次遍历一个元素。

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

于 2012-09-01T19:51:15.657 回答
1

您可以通过执行以下操作来避免制作数组的副本:

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

        i --;
        continue;
    }
}
于 2012-09-01T19:57:35.480 回答
1

您应该使用集合而不是数组。然后你可以复制set,操作完成后,拿一个diff看看有什么变化。

于 2012-09-01T20:03:06.403 回答
0

我制作了一个名为的宏smartFor,它允许您进行与 for 循环快速枚举相同的设置,但可以处理数组的修改。它利用了一些 C 和 CLANG 漏洞利用,非常简单和干净。


宏:

///Allows for modifying an array during virtual fast enumeration
#define smartFor(__objectDeclaration, __array, __block) {\
int __i = 0;\
while (__i < __array.count) {\
__objectDeclaration = __array[__i];\
NSObject *__object = __array[__i];\
[__block invoke];\
if ([__array indexOfObjectIdenticalTo:__object] != NSNotFound && ((int)[__array indexOfObjectIdenticalTo:__object]) <= __i) {\
__i = ((int)[__array indexOfObjectIdenticalTo:__object])+1;\
}\
}\
}

它会自动处理您可能会做的所有 [基本] 不稳定的事情,例如添加对象(在数组中的任何位置,在“快速枚举” [1]期间的任何时间点)、删除对象、调整对象的索引、修改对象等.


示例用法:

smartFor(NSNumber *aNumber, myArray, ^{
    if ([aNumber isEqualToNumber:@(3)]) {
        [myArray removeObjectIdenticalTo:aNumber];
    }
});

[1]注意:显然,在严格的定义/性能基础上,它在技术上并不是快速枚举,但在所有意图和目的上都表现得像它一样

于 2019-08-28T06:01:59.497 回答