简体   繁体   中英

Strange NSRangeException beyond bounds error in NSMutablearray

In my app, I'm doing audio analysis. Every second, I'm calling some methods, like this one :

- (NSNumber *) arrayAverage: (NSMutableArray *)array
{
    int countArray = [array count];

    if(!countArray)
        return nil;

    else if (countArray <= 5 )
        return [array valueForKeyPath:@"@avg.doubleValue"];

    else
    {
        // Création et initialisation d'un tableau temporaire
        NSMutableArray *averageArray = [[NSMutableArray alloc] initWithArray:array];
        NSSortDescriptor* desc = [[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES];
        [averageArray sortUsingDescriptors:[NSArray arrayWithObject:desc]];


        for (int j = 0; j < countArray / 3; j++)
        {
            [averageArray removeLastObject];
            [averageArray removeObjectAtIndex:0];
        }


        NSNumber * average = [averageArray valueForKeyPath:@"@avg.doubleValue"];


        return average;
        }

}

The problem is that I sometime receive a NSRangeException error (after 1min or a few hours...it depends...) saying that the array index is beyond bounds. The strange thing is that the index is NOT out of bounds... Those methods are only called on the main thread. Thanks in advance for your help !

EDIT 1 : With the help of Anim and Abhinav, I have changed my code as following. It has worked for more than 2hours 45min (which is a record) and then crash with a EXC_BAD_ACCESS code 1 error...

- (NSNumber *) arrayAverage: (NSMutableArray *)array
{
    NSArray *arrayCopy = [[NSArray alloc] initWithArray:array]; // CRASH with EXC_BAD_ACCESS error

    int countArray = [arrayCopy count];

    if(!countArray)
        return nil;

    else if (countArray <= 5 )
        return [arrayCopy valueForKeyPath:@"@avg.doubleValue"];

    else
    {
        // Création et initialisation d'un tableau temporaire
        NSMutableArray *averageArray = [[NSMutableArray alloc] initWithArray:arrayCopy];
        NSSortDescriptor* desc = [[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES];
        [averageArray sortUsingDescriptors:[NSArray arrayWithObject:desc]];

        int startOfRange = countArray / 3;
        int rangeLength = countArray - 2 * (countArray / 3);

        NSArray* slicedArray = [averageArray subarrayWithRange:NSMakeRange(startOfRange, rangeLength)];

        NSNumber * average = [slicedArray valueForKeyPath:@"@avg.doubleValue"];

        return average;
    }

}

With given piece of code it would more of guessing on whats going on here. Please make sure following:

  1. Before calling "removeLastObject" or "removeObjectAtIndex", it makes sense to put a check on the array count. Call them only when there is something to remove.
  2. Given that NSArray and NSMutableArray are not thread safe, make sure that the arrays you are operating on are not getting modified and used at the same time.

I would like to induce following statements inside your For loop:

if (averageArray.count > 0) {
    [averageArray removeLastObject];
}

if (averageArray.count > 0) {
    [averageArray removeObjectAtIndex:0];
}

you can do one more thing, just add one condition before the loop: here is the snippet, have added comment:

- (NSNumber *) arrayAverage: (NSMutableArray *)array
{
    int countArray = [array count];

    if(!countArray)
        return nil;

    else if (countArray <= 5 )
        return [array valueForKeyPath:@"@avg.doubleValue"];

    else
    {
        // Création et initialisation d'un tableau temporaire
        NSMutableArray *averageArray = [[NSMutableArray alloc] initWithArray:array];
        NSSortDescriptor* desc = [[NSSortDescriptor alloc] initWithKey:@"self" ascending:YES];
        [averageArray sortUsingDescriptors:[NSArray arrayWithObject:desc]];

       if ([array count] > 0)  //Added one condition here---PR Singh
      { 
          for (int j = 0; j < countArray / 3; j++)
          {
             [averageArray removeLastObject];
             [averageArray removeObjectAtIndex:0];
          }
      }


        NSNumber * average = [averageArray valueForKeyPath:@"@avg.doubleValue"];


        return average;
        }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM