【问题标题】:What in my code is causing this error (NSMutableArray is to small for the object being called)?我的代码中的什么导致了这个错误(NSMutableArray 对于被调用的对象来说太小了)?
【发布时间】:2011-10-30 06:52:28
【问题描述】:

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

这里是错误:*** 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];
    }
}

【问题讨论】:

    标签: iphone arrays memory nsmutablearray nsarray


    【解决方案1】:

    我相信,在 animationEnded 中,您尝试删除图像 #7 7 次。

    编辑:更多信息...

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

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

    【讨论】:

    • 哎呀我忘了包括这个我很抱歉,但我忘了包括这行代码: - (void)startEmitting { generateTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self 选择器:@selector (onTimer) userInfo:nil repeats:YES]; }
    • 不过,问题在于“num”的分配和元素的删除——你总是删除元素 #7,如 Paul.s 的回答所示。
    • 好的 - 我没有看到你传递了 'num' - 仍然存在删除元素的问题......我要查找一些内容,然后我会更新我的答案。
    • 非常感谢,但我看到了你写的内容,你知道我将如何修复它,因为根据计时器的不同,它们的总图像数量可能会有所不同跨度>
    【解决方案2】:

    如果你像这样在animationEnded 方法中添加NSLog

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

    您会看到每次运行都会注销循环产生的最大数字,即 7。

    所以第一次删除索引 7 处的对象很好,但第二次删除索引 7 时,只有 [0 .. 6] 个项目

    【讨论】:

      【解决方案3】:

      尝试在动画结束时使用计时器触发方法是不明智的。相反,您应该在动画块中使用 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:

      【讨论】:

        猜你喜欢
        • 2014-08-04
        • 1970-01-01
        • 2011-10-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-07-16
        相关资源
        最近更新 更多