Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSGenericException reason Collection <NSConcreteMapTable: xxx>

this is the error that i see when present SKScene, this error occurs randomly and are not able to replicate

* Terminating app due to uncaught exception 'NSGenericException', reason: '* Collection < NSConcreteMapTable: 0x1459da60 > was mutated while being enumerated.'

what's happen?

tell me if you need any other info

thanks

EDIT:

*** First throw call stack:
(
    0   CoreFoundation                      0x025601e4 __exceptionPreprocess + 180
    1   libobjc.A.dylib                     0x022298e5 objc_exception_throw + 44
    2   CoreFoundation                      0x025efcf5 __NSFastEnumerationMutationHandler + 165
    3   Foundation                          0x01e47f03 -[NSConcreteMapTable countByEnumeratingWithState:objects:count:] + 66
    4   CoreFoundation                      0x0253d77f -[__NSFastEnumerationEnumerator nextObject] + 143
    5   SpriteKit                           0x01d009f2 +[SKTextureAtlas(Internal) findTextureNamed:] + 232
    6   SpriteKit                           0x01cf709c __26-[SKTexture loadImageData]_block_invoke + 1982
    7   SpriteKit                           0x01d34d09 _Z14SKSpinLockSyncPiU13block_pointerFvvE + 40
    8   SpriteKit                           0x01cf6898 -[SKTexture loadImageData] + 228
    9   SpriteKit                           0x01cf65d9 __51+[SKTexture preloadTextures:withCompletionHandler:]_block_invoke + 241
    10  libdispatch.dylib                   0x02b117b8 _dispatch_call_block_and_release + 15
    11  libdispatch.dylib                   0x02b264d0 _dispatch_client_callout + 14
    12  libdispatch.dylib                   0x02b14eb7 _dispatch_root_queue_drain + 291
    13  libdispatch.dylib                   0x02b15127 _dispatch_worker_thread2 + 39
    14  libsystem_c.dylib                   0x02de1e72 _pthread_wqthread + 441
    15  libsystem_c.dylib                   0x02dc9daa start_wqthread + 30
)
libc++abi.dylib: terminating with uncaught exception of type NSException
like image 340
Ilario Avatar asked Mar 18 '14 13:03

Ilario


4 Answers

I get the same exception on occasion. It's been around for a while and I've been trying to pinpoint it for weeks.

My suspicion is that it may occur due to preloading textures, either manually or triggered automatically by Sprite Kit while at the same time some other code causes textures to be loaded or accessed.

I have reduced my preloadTextures: calls to a single one but I still get the issue, just less often. I have tried to performSelector:onMainThread: whenever I run a selector that accesses or loads images (or just might internally) from within a completionBlock or other code that runs on a different thread.

I haven't had this crash the entire day today after I moved my user interface code to the main thread (it was called from a completion handler). I can't say 100% for sure whether this fixed it though.

I hope this helps a little. There's definitely something finicky going on, and if you do po 0x1459da60 (in lldb's command window, using the address provided by the exception) you'll see that it is the SKTextureAtlas texture list that is being modified. I hope that helps you pinpoint where the issue is coming from on your side.

like image 196
LearnCocos2D Avatar answered Oct 22 '22 15:10

LearnCocos2D


From what I can tell this a sprite kit bug in the sprite kit method:

preloadTextures: withCompletionHandler:

The only way I was able to fix this was by removing this method completely. According to apple docs the textures also get loaded if you access the size property. So my workaround is just to do exactly that:

for (SKTexture *texture in self.texturesArray) {
    texture.size;
}

It's not pretty but it works!

like image 4
Zalykr Avatar answered Oct 22 '22 15:10

Zalykr


I had the same problem, when I tried to preload two simple animations. I tried to preload the animations in a dictionary and have them ready to be called via a string key. Here is what I tried

-(void)setupAnimDict {
    animDict = [[NSMutableDictionary alloc] init];

    [animDict setObject:[self animForName:@"blaze" frames:4] forKey:@"blaze"];
    [animDict setObject:[self animForName:@"flame" frames:4] forKey:@"flame"];
}

-(SKAction *)animForName:(NSString *)name frames:(int)frames {
    NSArray *animationFrames = [self setupAnimationFrames:name base:name num:frames];
    SKAction *animationAction = [SKAction animateWithTextures:animationFrames     timePerFrame:0.10 resize:YES restore:NO];
    return [SKAction repeatActionForever:animationAction];
}

-(NSArray *)setupAnimationFrames:(NSString *)atlasName base:(NSString *)baseFileName num:(int)numberOfFrames {

    [self preload:baseFileName num:numberOfFrames];

    NSMutableArray *frames = [NSMutableArray arrayWithCapacity:numberOfFrames];
    SKTextureAtlas *atlas = [SKTextureAtlas atlasNamed:atlasName];
    for (int i = 0; i < numberOfFrames; i++) {
        NSString *fileName = [NSString stringWithFormat:@"%@%01d.png", baseFileName, i];
        [frames addObject:[atlas textureNamed:fileName]];
    }

    return frames;
}

-(void)preload:(NSString *)baseFileName num:(int)numberOfFrames {

    NSMutableArray *frames = [NSMutableArray arrayWithCapacity:numberOfFrames];

    for (int i = 0; i < numberOfFrames; i++) {
        NSString *fileName = [NSString stringWithFormat:@"%@%01d.png", baseFileName, i];
        [frames addObject:[SKTexture textureWithImageNamed:fileName]];
    }

    [SKTexture preloadTextures:frames withCompletionHandler:^(void){}];
}

When I called the setupDict method I sometimes got the same error as you. The problem was that preloading of my two animations run into each other. I got rid of the error by changing the

[SKTexture preloadTextures:frames withCompletionHandler:^(void){}];

to

if ([baseFileName isEqualToString:@"blaze"]) {
        [SKTexture preloadTextures:frames withCompletionHandler:^{
            [self setupFlame];
        }];
    } else {
        [SKTexture preloadTextures:frames withCompletionHandler:^(void){}];
    }

so that the first preloading was done before I attempted to preload the other.

I don't know if this is your problem, but if it is let us know.

like image 2
Bob Ueland Avatar answered Oct 22 '22 13:10

Bob Ueland


Same thing still happening for me in Xcode 6.3 beta / Swift 1.2. Here is a temporary fix that has worked for me.

SKTextureAtlas.preloadTextureAtlases([SKTextureAtlas(named: "testAtlas")], withCompletionHandler: {
    dispatch_async(dispatch_get_main_queue(), {
        handler()
    })
})

I actually wrapped this in a function so that all preloads route through it. That way if it gets fixed on the SpriteKit side, or if there are major flaws with this approach, I can remove the dispatch.

like image 1
Ryan C Avatar answered Oct 22 '22 13:10

Ryan C