我的代码中是什么导致了这个错误(对于被调用的对象,NSMutableArray是小的)?

时间:2011-08-19 02:21:33

标签: iphone arrays memory nsmutablearray nsarray

我假设在我的代码中的某个地方,数组中的对象被删除的速度比创建它们的速度快。我一直在寻找这个问题超过一个小时所以请帮忙!

以下是错误:*** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[NSMutableArray objectAtIndex:]: index 7 beyond bounds [0 .. 6]' 在此先感谢,这是我的代码:

- (void)onTimer {
    UIImageView *imgView = [[UIImageView alloc] init];
    imgView.image = particleImg;
    imgView.frame = CGRectMake(kViewDimensions/2, kViewDimensions/2, startSize.width, startSize.height);
    [self addSubview:imgView];
    [particlesArray addObject:imgView];
    [imgView release];
    moveTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(moveObjs) userInfo:nil repeats:YES];
}
- (void)moveObjs {
    for (int i = 0; i < [particlesArray count]; i++) {
        animID = @"MoveId";
        UIImageView *imgV = [particlesArray objectAtIndex:i];
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.3];
        CGPoint randPoint = CGPointMake(arc4random()%kMaxRandX, arc4random()%kMaxRandY);
        imgV.center = CGPointMake(randPoint.x, randPoint.y);
        [UIView commitAnimations];
        animValue = i;
        num = [NSNumber numberWithInt:animValue];
        [NSTimer scheduledTimerWithTimeInterval:0.3 target:self selector:@selector(animationEnded) userInfo:num repeats:NO];
        NSLog(@"\n %d",animValue);
    }
}
- (void)animationEnded {   
    int av = [num intValue];
    UIImageView *iv = [particlesArray objectAtIndex:av];
    if ([animID isEqualToString:@"MoveId"]) {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.1];
        iv.alpha = 0.0f;
        [UIView commitAnimations];
        [particlesArray removeObjectAtIndex:av];
    }
    else {
        [iv removeFromSuperview];
    }
}

3 个答案:

答案 0 :(得分:0)

在animationEnded中,你试图删除图片#7 7次,我相信。

编辑:更多信息......

循环遍历moveObjs中的每个图像(0 ... n),在每次迭代中使用新值重新分配'num'。所以在最后一次迭代中(基于错误,我假设i = 7,总共8个图像),num保留在7。

当动画结束时,调用animationEnded,将num转回int(av),并删除索引'av'处的元素。

答案 1 :(得分:0)

如果您在NSLog方法中添加animationEnded,就像这样

- (void)animationEnded 
{   
    int av = [num intValue];
    NSLog(@"index => %i", av);

    // more stuff
}

您将看到,对于每次运行,它将注销由循环产生的最高数字,即7。

所以第一次在索引7处移除对象是正常的,但是当第二次在仅有[0 .. 6]项时再次移除索引7时

答案 2 :(得分:0)

尝试使用计时器在动画结束时触发方法是不明智的。相反,您应该在动画块中使用setAnimationDidStopSelector:类方法。最重要的是,由于您使用num来处理从数组中删除对象的方式,因此您可以保证在animationEnded的一个调用期间的某个时刻超过数组的边界。最好引用对象本身,而不是它在数组中的位置。这就是beginAnimations:context:方法中的上下文参数的用途:

- (void)moveObjs {
    for (int i = 0; i < [particlesArray count]; i++) {
        animID = @"MoveId";

        UIImageView *imgV = [particlesArray objectAtIndex:i];

        [UIView beginAnimations:nil context:imgV];
        [UIView setAnimationDuration:0.3];
        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];

        CGPoint randPoint = CGPointMake(arc4random()%kMaxRandX, arc4random()%kMaxRandY);
        imgV.center = CGPointMake(randPoint.x, randPoint.y);

        [UIView commitAnimations];
    }
}

- (void)animationDidStop:(NSString *)animID finished:(NSNumber *)finished context:(void *)context {   
    UIImageView *iv = (UIImageView *)context;

    if ([animID isEqualToString:@"MoveId"]) {
        [UIView beginAnimations:nil context:NULL];
        [UIView setAnimationDuration:0.1];
        iv.alpha = 0.0f;
        [UIView commitAnimations];
        [particlesArray removeObject:iv];
    } else {
        [iv removeFromSuperview];
    }
}

注意:如果您不支持iOS 4之前的版本,则应切换到使用基于块的新方法,例如animateWithDuration:animations:completion: