Ios – ‘NSGenericException’, reason: Collection <__NSArrayM: 0x7fabb400> was mutated while being enumerated

iosobjective c

In my iPhone app,i am trying to implement a image gallery using uicollectionView .when <20 images stores in gallery its working fine but when i am storing multiple image(greater than 20) app crashes.please help me.thanks in advance.

Error:

Terminating app due to uncaught exception 'NSGenericException', reason:          '*** Collection <__NSArrayM: 0x7fabb400> was mutated while being enumerated.'
*** First throw call stack:
(
    0   CoreFoundation                      0x042ea946 __exceptionPreprocess + 182
    1   libobjc.A.dylib                     0x03660a97 objc_exception_throw + 44
    2   CoreFoundation                      0x042ea1e6 __NSFastEnumerationMutationHandler + 166
    3   CoreFoundation                      0x041da052 -[NSArray containsObject:] + 178
    4   AtSceneDebug                        0x001ce9a9 -[GalleryCollectionViewController loadImageFromAppSupport:] + 201
    5   AtSceneDebug                        0x001c5de2 __73-[GalleryCollectionViewController collectionView:cellForItemAtIndexPath:]_block_invoke + 98
    6   libdispatch.dylib                   0x03cca30a _dispatch_call_block_and_release + 15
    7   libdispatch.dylib                   0x03ceae2f _dispatch_client_callout + 14
    8   libdispatch.dylib                   0x03cd310f _dispatch_root_queue_drain + 634
    9   libdispatch.dylib                   0x03cd487e _dispatch_worker_thread2 + 45
    10  libsystem_pthread.dylib             0x04056dab _pthread_wqthread + 336
    11  libsystem_pthread.dylib             0x0405acce start_wqthread + 30
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Code:

GalleryCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"GalleryCollectionViewCellID" forIndexPath:indexPath];

    if(indexPath.row==0)
    {
        Photo *photo=[self.photoSource.photos objectAtIndex:indexPath.row];
        cell.selectionImageView.hidden=YES;
        [cell.galleryImageView setImage:[UIImage imageNamed:[photo.mURLLarge lastPathComponent]]];
        return cell;
    }

    Photo *photo=[self.photoSource.photos objectAtIndex:indexPath.row];

    if(self.mItemType==ITEM_TYPE_PHOTO)

    {
        NSLog(@"index of coll.......%d",indexPath.row);
        UIImage *image = [_imageCache objectForKey:photo.mURLThumb];
      if(image)
        {
           //[cell.galleryImageView setImage:[self loadImageFromAppSupport:photo.mURLLarge]];
          [cell.galleryImageView setImage:image];

        }
      else
      {        
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{          
              UIImage *image = [self loadImageFromAppSupport:photo.mURLThumb];
              if(image)
              {
                  dispatch_async(dispatch_get_main_queue(), ^{
                      GalleryCollectionViewCell *cell =(GalleryCollectionViewCell*)[self.collectionView cellForItemAtIndexPath:indexPath];
                      if(cell)
                      {
                          cell.galleryImageView.image = image;
                      }
                  });

                  [_imageCache setObject:image forKey:photo.mURLThumb];
              }
          });

      }
    }

    else

    {
        [cell.galleryImageView setImage:[self loadImageFromAppSupport:photo.mURLThumb]];

    }

    if(indexPath.row==0)
    {
        cell.selectionImageView.hidden=YES;
    }
    else if(self.isEditing && photo.isMarkedForDeletion && indexPath.row!=0)
    {
        cell.selectionImageView.hidden=NO;
        [cell.selectionImageView setImage:[UIImage imageNamed:@"red_led"]];
    }
    else if (self.isEditing && !photo.isMarkedForDeletion && indexPath.row!=0)
    {
        //[cell.selectionImageView setImage:[UIImage imageNamed:@"green_led"]];
        cell.selectionImageView.hidden=YES;
    }
    else if(!self.isEditing && photo.isMarkedForDeletion && indexPath.row!=0)
    {
        cell.selectionImageView.hidden=YES;
    }
    else if(!self.isEditing && !photo.isMarkedForDeletion && indexPath.row!=0)
    {
        cell.selectionImageView.hidden=YES;
    }

    if (!self.isEditing)
    {
        CGFloat xx=cell.frame.origin.x;
        CGFloat yy=cell.frame.origin.y;

        CGRect frame = cell.frame;
        frame.origin.x = 500; // new x coordinate
        frame.origin.y = 0; // new y coordinate
        cell.frame = frame;

                [UIView animateWithDuration:0.0 animations:^{

            CGRect frame = cell.frame;
            frame.origin.x = xx; // new x coordinate
            frame.origin.y = yy; // new y coordinate
            cell.frame = frame;
        }];

    }
    cell.layer.shouldRasterize = YES;
    cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
    return cell;

Best Answer

This error is often thrown when you use a NSMutable on 2 different thread/queue, and one is enumerating one while the other is adding / removing element from it. You should never use NSMutableObject in a multi threaded environment. Your call:

[_imageCache setObject:image forKey:photo.mURLThumb];

is the reason for the failure,you are changing a mutable object in a dispatch queue while accessing it in the main thread. Move this call just above the "if(cell)" part (or anywhere else in the dispatch_get_main_queue block) will solve it.