【问题标题】:Xcode exception: "Collection <__NSArrayM: 0xb1a2970> was mutated while being enumerated" with Mutable ArraysXcode 异常:“集合 <__NSArrayM: 0xb1a2970> 在枚举时发生了变异”与可变数组
【发布时间】:2012-05-30 01:51:43
【问题描述】:

我遇到了三个类的问题。第一类称为Player。这个类里面有一个NSMutableArray,叫做units。该数组由Unit 类的对象组成。反过来,这个类有一个名为bulletsNSMutableArray。它的工作原理是这样的:

在某个时刻,Player 类(它可能只是 ViewController)将一个对象添加到 units。然后,当Unit 的实例被初始化时,由于上述原因,它创建了一个负责每秒创建子弹的NSTimer。

问题是,在这中间某处崩溃,SIGABRT 告诉我有一个异常,因为:Collection &lt;__NSArrayM: 0xb1a2970&gt; was mutated while being enumerated. 另外,我拿走了创建子弹的线,它停止崩溃,证明是问题所在。这是什么意思!

下面是一些可能有效的可执行代码:

ViewController.h(代替播放器)

@interface ViewController : UIViewController
{
    NSMutableArray *units;
    NSTimer *updateTimer;
}
-(void)Update;

ViewController.m

@implementation ViewController
//methods...

- (void)viewDidLoad
{
    //more default code

    //Initialized array and adds one object with the default constructor for simplicity
    units = [[NSMutableArray alloc] initWithObjects:[[Unit alloc] init], nil]
}

-(void)Update
{
    for(Unit *unit in units)
    {
        [unit Update];
        if(unit.deleteFromList)
            [units removeObject:unit];   
    }
}
//More methods
@end

单位.h

@interface Unit : NSObject
{
    NSMutableArray *bullets;
    NSTimer *bulletTimer;
    boolean deleteFromList;
}

@property(readonly, assign)deleteFromList;

-(void)Fire;

-(void)Update;

单位.m

@implementation Unit

@synthesize deleteFromList;

-(id)init
{
    if(self)
    {
        bullets = [[NSMutableArray alloc] init];
        bulletTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(fire) userInfo:NULL repeats:true];
        deleteFromList = false;
    }

    return self;
}

-(void)Fire
{
    [bullets addObject:[[Bullet alloc] init]];
}

-(void)Update
{
    for(Bullet *bullet in bullets)
    {
        [bullet Update];
        if(bullet.deleteFromList)
            [bullets removeObject:bullet];
    }

    if(certainCondition)
        deleteFromList = true;
}

子弹类将被省略,因为内容与发生的事情无关。此外,所有的类和构造函数都被缩短了,因为其余的对于这个例子是无用的

编辑:

我忘记添加的另一件事是,计时器是在我即将添加的更新方法中的 NSMutableArray 单元的枚举中创建的。我还向 Unit 和 Bullet 添加了一个变量,命令它删除。子弹更新改变了位置,也改变了 deleteFromList 变量

【问题讨论】:

  • 你什么时候枚举bullets
  • 完全不拍会不会出现这个问题?
  • 不,如果我评论创建项目符号的行,它可以工作

标签: xcode exception nsmutablearray sigabrt


【解决方案1】:

在 for 循环或枚举 NSMutableArray 时,您不能删除任何项目。

文档:It is not safe to modify a mutable collection while enumerating through it. Some enumerators may currently allow enumeration of a collection that is modified, but this behavior is not guaranteed to be supported in the future.

for(Bullet *bullet in bullets)
{
    [bullet Update];
    if(bullet.deleteFromList)
        [bullets removeObject:bullet];
}

NSMutableArray *toRemove = [NSMutableArray array];
for(Bullet *bullet in bullets)
{
    [bullet Update];
    if(bullet.deleteFromList)
        [toRemove addObject:bullet];
}
[bullets removeObjectsInArray:toRemove];

【讨论】:

  • 你有什么替代方案可以帮到我吗?正常的 for 循环会起作用吗?
  • 谢谢,问题解决了。
【解决方案2】:

有两种简单的方法 - 一种是创建要删除的对象数组,另一种是迭代原始方式的副本。第二种技术可能更容易阅读。

方法一

NSMutableArray *toRemove = [NSMutableArray array];
for (Bullet *bullet in bullets)
{
    [bullet Update];
    if (bullet.deleteFromList)
    {
        [toRemove addObject:bullet];
    }
}
[bullets removeObjectsInArray:toRemove];

方法二

for (Bullet *bullet in [bullets copy])
{
    [bullet Update];
    if (bullet.deleteFromList)
    {
        [bullets removeObject:bullet];
    }
}

第一种方法稍微冗长一些,但不会复制原始数组。如果原始数组非常大,并且出于性能/内存原因不想复制它,第一种方法是最好的。如果没关系(99% 的时间),我更喜欢第二种方法。


顺便说一句,您不应该在 Objective-C 中以大写字母开头方法名称,除非方法名称以缩写开头,例如URL,所以[bullet Update]真的应该重命名为[bullet update]

【讨论】:

  • 方法二好可爱,我喜欢! copy后面还需要[bullets release]吗?
  • 如果你不使用 ARC,你应该使用[[bullets copy] autorelease]
【解决方案3】:

或者

NSIndexSet *indexSet = [units indexesOfObjectsPassingTest:^BOOL(Unit *udit, NSUInteger idx, BOOL *stop) {
    [unit Update];
    return unit.deleteFromList;
}];

[units removeObjectsAtIndexes:indexSet];

【讨论】:

    猜你喜欢
    • 2017-11-22
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 1970-01-01
    • 2013-01-29
    相关资源
    最近更新 更多