Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is SKSpinLockSync in Sprite Kit and how do I fix it

I am receiving a bug report with the following stack trace and I have no idea what the problem is. I've seen suggestions that this could be caused by having an emitter's image in a texture atlas or by removing an emitter in the same run loop as it is added but I don't think either of these is happening. It's a sporadic issue and I can't recreate it. I only see it in bug reports. I would love any help.

0    libsystem_platform.dylib    OSSpinLockLock + 1
1    SpriteKit   SKSpinLockSync(int*, void ()() block_pointer) + 92
2    SpriteKit   -[SKTexture loadImageData] + 300
3    SpriteKit   -[SKTexture size] + 42
4    SpriteKit   SKCEmitterSprite::update(double) + 3136
5    SpriteKit   SKCSprite::update(double) + 354
6    SpriteKit   SKCSprite::update(double) + 354
7    SpriteKit   -[SKScene _update:] + 174
8    SpriteKit   -[SKView(Private) _update:] + 324
9    SpriteKit   -[SKView renderCallback:] + 820
10   SpriteKit   __29-[SKView setUpRenderCallback]_block_invoke + 130
11   SpriteKit   -[SKDisplayLink _callbackForNextFrame:] + 254
12   QuartzCore  CA::Display::DisplayLinkItem::dispatch() + 98
13   QuartzCore  CA::Display::DisplayLink::dispatch_items(unsigned long long, unsigned long long, unsigned long long) + 344
14   IOMobileFramebuffer     IOMobileFramebufferVsyncNotifyFunc + 104
15   IOKit   IODispatchCalloutFromCFMessage + 248
16 ...   CoreFoundation  __CFMachPortPerform + 136
17   CoreFoundation  __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__ + 34
18   CoreFoundation  __CFRunLoopDoSource1 + 346
19   CoreFoundation  __CFRunLoopRun + 1406
20   CoreFoundation  CFRunLoopRunSpecific + 524
21   CoreFoundation  CFRunLoopRunInMode + 106
22   GraphicsServices    GSEventRunModal + 138
23   UIKit   UIApplicationMain + 1136
24   myApplication  main.m line 16  main

EDIT: I'm now realizing that I get the SKSpinLockSync problem in a few different situations and not always with the emitters. I think that the only reason that I see it so often with the emitter is because that is the lions share of the image loading in the app so it's just the statistically most likely. The top four lines of the stack trace are always the same. So, up to and including [SKTexture Size].

like image 771
Kardasis Avatar asked Oct 18 '13 12:10

Kardasis


People also ask

Is SpriteKit still supported?

SpriteKit is supported on iOS, macOS, tvOS, and watchOS, and it integrates well with frameworks such as GameplayKit and SceneKit.

What is the difference between SceneKit and SpriteKit?

SceneKit and SpriteKit are very similar to each other. SceneKit is a little harder to learn but it's pretty simple. SceneKit would be the only way to have a 3D model(With the options you provided). You can have a SpriteKit scene over top of the SceneKit scene to display labels that stay put.

What is SpriteKit in iOS?

The SpriteKit framework makes it easy to create high-performance, battery-efficient 2D games. With support for custom OpenGL ES shaders and lighting, integration with SceneKit, and advanced new physics effects and animations, you can add force fields, detect collisions, and generate new lighting effects in your games.


1 Answers

I had the same problem and I found that when I call

NSString *p = [[NSBundle mainBundle] pathForResource:name ofType:@"sks"];  
SKEmitterNode *e = [NSKeyedUnarchiver unarchiveObjectWithFile:p];  

many times, it will randomly crash the app with the same crash log

SKSpinLockSync(int*, void ()() block_pointer) + 36  
-[SKTexture loadImageData] + 252  
-[SKTexture size] + 44  
SKCEmitterSprite::update(double) + 2928  

I think this is Sprite Kit problem and hope Apple will fix this soon

My solution is : don't call unarchiveObjectWithFile everytime

unarchiveObjectWithFile may relate to IO and this may crash if you do that too often like every frame in your game, or the problem come from SKTexture cache system has problem when it need texture data and call loadImageData in non-thread safe.

So I reuse SKEmitterNode with copy, here is my function

// Emitter Pool
- (SKEmitterNode*)getEmitter:(NSString*)name {
    if(!mDictEmitter)
        self.mDictEmitter = [NSMutableDictionary new];
    SKEmitterNode *e = [mDictEmitter objectForKey:name];
    if(!e){
        NSString *p = [[NSBundle mainBundle] pathForResource:name ofType:@"sks"];
        e = [NSKeyedUnarchiver unarchiveObjectWithFile:p];
        [mDictEmitter setObject:e forKey:name];
    }
    return [e copy];
}
like image 94
saranpol Avatar answered Sep 22 '22 10:09

saranpol