NSArraym was mutated while being enumerated, sqlite3 while loop?

356 views Asked by At

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

1

There are 1 answers

1
CodeSmile On BEST ANSWER

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.