The collection was mutated while an error was recorded in the C object

Below is my code.

NSMutableArray *arr = [[NSMutableArray alloc] init]; [arr addObject:@"5"]; [arr addObject:@"7"]; [arr addObject:@"8"]; [arr enumerateObjectsUsingBlock:^(NSString *obj,NSUInteger idx,BOOL *stop) { [arr replaceObjectAtIndex:idx withObject:@"10"]; }]; 

In the exception log I got

  *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x742a580> was mutated while being enumerated.' *** First throw call stack: (0x1596012 0x12a3e7e 0x161ecc5 0x158fe1b 0x158fa16 0x158f925 0x2ba4 0x1e87b7 0x1e8da7 0x1e9fab 0x1fb315 0x1fc24b 0x1edcf8 0x25f8df9 0x25f8ad0 0x150bbf5 0x150b962 0x153cbb6 0x153bf44 0x153be1b 0x1e97da 0x1eb65c 0x29fd 0x2925) libc++abi.dylib: terminate called throwing an exception 0x1e87b7 0x1e8da7 0x1e9fab 0x1fb315 0x1fc24b 0x1edcf8 0x25f8df9 0x25f8ad0 0x150bbf5 0x150b962 0x153cbb6 0x153bf44 0x153be1b 0x1e97da 0x1eb65c 0x29fd 0x2925)  *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x742a580> was mutated while being enumerated.' *** First throw call stack: (0x1596012 0x12a3e7e 0x161ecc5 0x158fe1b 0x158fa16 0x158f925 0x2ba4 0x1e87b7 0x1e8da7 0x1e9fab 0x1fb315 0x1fc24b 0x1edcf8 0x25f8df9 0x25f8ad0 0x150bbf5 0x150b962 0x153cbb6 0x153bf44 0x153be1b 0x1e97da 0x1eb65c 0x29fd 0x2925) libc++abi.dylib: terminate called throwing an exception 

The code works fine when I use for loop

 for (int i = 0 ; i< arr.count; i++) { [arr replaceObjectAtIndex:i withObject:@"8"]; } 

So while I use enumerateObjectsUsingBlock, I get an exception. But both are enumerations. Right? Then why does the top code throw an exception was mutated while being enumerated ?

+6
source share
6 answers

Because your logic is wrong. When listing, it is not allowed to mutate the collection. And in the latter case, NSMutableArray does not know that you are trying to fix it, only in the first case. And then he complains, as this is a semantic mistake. Usually you should solve these problems by mutually copying the array and modifying the copy, and then replacing the original with the updated copy.

+11
source

You cannot do this:

 [arr enumerateObjectsUsingBlock:^(NSString *obj,NSUInteger idx,BOOL *stop) { [arr replaceObjectAtIndex:idx withObject:@"10"]; }]; 

Because you cannot mutate a collection while you list it.

I suggest putting all operations in the operation queue and execute them after listing:

 NSOperationQueue* queue= [NSOperationQueue new]; queue.maxConcurrentOperationCount=1; [queue setSuspended: YES]; [arr enumerateObjectsUsingBlock:^(NSString *obj,NSUInteger idx,BOOL *stop) { NSBlockOperation* op=[NSBlockOperation blockOperationWithBlock: ^ (void) { [arr replaceObjectAtIndex:idx withObject:@"10"]; }]; [queue addOperation: op]; }]; [queue setSuspended: NO]; [queue waitUntilAllOperationsAreFinished]; 

Another method would be to simply all the elements in another collection and delete them later. That would be easier to write.

+6
source

You cannot modify a collection using quick enumeration. I wrote a post about a change in the listing , which should be useful.

Thought, looking at her again, I never spoke of a replacement, listing. You can still save indexes and objects and use replaceObjectsAtIndexes:withObjects: after listing.

 NSMutableArray *array = // ... NSMutableIndexSet *indicesForObjectsToReplace = [NSMutableIndexSet new]; NSMutableArray *objectsToReplace = [NSMutableArray new]; [array enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) { [indicesForObjectsToRemove addIndex:idx]; [objectsToReplace: @"String you are replacing with"]; }]; [array replaceObjectsAtIndexes:indicesForObjectsToReplace withObjects:objectsToReplace]; 
+3
source

Just add break; after removing your element from the array.

  for (NSDictionary *dic in ticketsToBuyArray) { if ([[[dic objectForKey:@"ticket_id"]stringValue] isEqualToString:[[ticketDictionary objectForKey:@"ticket_id"]stringValue]]) { [ticketsToBuyArray removeObject:dic]; break; } } 
+2
source

A quick listing makes the collection immutable . Therefore, whenever you use for(.. in ..) or block and try to mutate, you will get this error.

Whenever you need to update a collection while it is scrolling, you need to take the modified collection and use the usual for (;;), or dowhile loops. for( .. in ..) makes your mutable collection immutable at runtime.

+1
source

I have little experience with objective-c, but it is usually an enumerator class function that prevents an enumerated enumerated object between iterations of an enumeration.

The enumerator class checks to see if the enumerated object has performed the mutating method, for example, add, delete, or replace before returning the next instance from the collection. And the foreach loop is usually implemented based on an enumerator and enumerated classes (or interfaces).

Indexed access to an array element is a method of embedded arrays, a basic operation that does not require any additional mechanism.

0
source

All Articles