1

I get the error: NSArrayM was mutated while being enumerated and I've tried almost Everything I could find on stackoverflow. Keep in mind that I'm learning as I create my game :)

I'm using sprite kit and uses dispatch_async in didmovetoview to load the game.

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void){
       // loading stuff, but also this that is causing the error:
       [self buildmap];
    dispatch_async(dispatch_get_main_queue(), ^(void){
        // done loading
    });
});

Here is the buildmap that causes the crash.

-(void)buildMap {

    int intX = 0;
    int intY = 0;

    sqlite3_stmt *statement;
    if (sqlite3_open([_databasePath UTF8String], &BlockMinerDB) == SQLITE_OK) {

        NSString *sql = [NSString stringWithFormat:@"SELECT blocktype, ladder, blockreachable, walkable, zpos, texture, id, bitmask FROM map ORDER BY id DESC"];
        const char *qstmt = [sql UTF8String];

        if (sqlite3_prepare_v2(BlockMinerDB, qstmt, -1, &statement, NULL) == SQLITE_OK) {

            while (sqlite3_step(statement) == SQLITE_ROW) {

                int blockType = sqlite3_column_int(statement, 0);
                int ladder = sqlite3_column_int(statement, 1);
                int blockReachable = sqlite3_column_int(statement, 2);
                int walkable = sqlite3_column_int(statement, 3);
                int zPos = sqlite3_column_int(statement, 4);
                NSString *texture = [NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 5)];
                int idBlock = sqlite3_column_int(statement, 6);
                uint32_t newBitmask = (uint32_t)[NSString stringWithUTF8String:(char*)sqlite3_column_text(statement, 7)];



                Blocks *testblock = [[Blocks alloc] initWithBlock:blockType blockId:idBlock ladder:ladder scene:self bitmask:newBitmask blockReachable:blockReachable walkable:walkable zPos:zPos texture:texture x:intX y:intY];

                NSLog(@"%@: %i", testblock.name, blockType);

                if ((blockType == 2) || (blockType == 3) || (blockType == 4) || (blockType == 5)) {
                    [blockArrayWalk addObject:testblock];
                } else {
                    [blockArray addObject:testblock];
                }


                [background addChild:testblock];
                intX++;
                if (intX == 25) {
                    intX = 0;
                    intY++;
                }
            }
        }
    }
    sqlite3_close(BlockMinerDB);
}

[self buildmap] uses sqlite to retreive the map from the database, i'm looping with a while loop and this is causing the crash. It loops about 20-25 times (of 600) Before crashing.

Within the loop I'm creating a new block (SKSpriteNode subclass) that places the block at an certain position with some information (position, name, physics and such, no Heavy stuff). I was using NSMutableArray to store the blocks for easy access and thought that this was the problem at first, but when I remove the [blockArray addObject:block]; the app still crashes.

If I remove every bit of code in the -(void)buildmap the app doesn't crash.

Is there something with dispatch_async and the while loop that might cause this?

I can't access the code right now but if anyone need to see more code, I can add this in about 8 hours from now ;) Would really appreciate some help, trying to solve this error for 3 weeks on and off now :D

Znyder
  • 51
  • 7
  • possible duplicate of [Objective-C NSMutableArray mutated while being enumerated?](http://stackoverflow.com/questions/8834031/objective-c-nsmutablearray-mutated-while-being-enumerated) – CodeSmile Nov 11 '14 at 08:54
  • I've removed any reference to nsmutablearray and it still produce this error. I dont add / remove objects from an nsmutablearray in buildmap that causes this error. – Znyder Nov 11 '14 at 08:56
  • post the code near where the error occurs, and highlight the line with the error – CodeSmile Nov 11 '14 at 09:00
  • Updated my question with buildup, the one that crashes the app :) – Znyder Nov 13 '14 at 05:50
  • So the error is in buildMap, but on what line exactly? Use the call stack (of the crashed thread) to find out. – CodeSmile Nov 13 '14 at 10:58
  • After a lot of debugging I realized its this code: [background addChild:testblock]; that causes the mutated error... Cant I add a node from the dispatch_async? – Znyder Nov 13 '14 at 18:17
  • Tricky, but the answer is probably *no* if the dispatch async block runs past the current frame. At any point in time Sprite Kit may be enumerating over children (perhaps to draw them) and if your dispatch block then adds a new child node, it would cause the children array to mutate while being enumerated. You could fill an array of to-be-added nodes in your dispatch block, and then after the dispatch block add them all at once. – CodeSmile Nov 13 '14 at 18:46
  • That did the trick! I already added the blocks into blockArrayWalk and blockArray. I did then loop the arrays in dispatch_get_main_queue() to add every node to background and it works perfectly. Thanks! I'm kinda new to Stackoverflow, how can I get this question answered and that you answered it? :) – Znyder Nov 13 '14 at 19:20
  • copy and pasted an answer ;) – CodeSmile Nov 13 '14 at 19:28

1 Answers1

1

At any point in time Sprite Kit may be enumerating over children (perhaps to draw them) and if your dispatch block then adds a new child node, it would cause the children array to mutate while being enumerated.

You could fill an array of to-be-added nodes in your dispatch block, and then after the dispatch block add them all at once.

CodeSmile
  • 64,284
  • 20
  • 132
  • 217