枚举时加载 SKTexture 崩溃发生变异

Loading SKTexutre Crash mutated while being enumerated

我在使用以下代码时遇到问题,该代码通过调用 SKTexture 的大小来加载它。在调用 size 的行中,每 100 次运行中大约有 1 次代码随机崩溃。还有一些其他的 SKTexture 方法可以预加载图像,但它们也会更频繁地导致崩溃!我使用 TextureAtlases 并防止崩溃,我所有的 SKTexure 加载都是通过这种方法发生的。

/* add image to dictionary thread-safe */
-(SKTexture*) getThreadSafeDictionaryContainImageOtherwiseLoadAndReturn:(NSString*) imageToLoad andForceLoad:(BOOL) forceLoad{

    // to control the enviroment where the image dictionary is modified, go ahead and lock it down with an NSLock
    [self.dictionaryModificationLock lock];

    SKTexture *toReturn = nil;
    CGSize size = CGSizeZero;

    // first, ignore duplicate loads by looking for the image in an NSDictionary called "allImages"
    if ((toReturn = [self.allImages objectForKey:imageToLoad])){
        // have the image to return already loaded

    }else{
        // grab the SKTexture and force it to load by requesting it's size
        SKTexture *texture = [SKTexture textureWithImageNamed:imageToLoad];
        if (forceLoad)
            size = texture.size; // crashes here!

        [self.allImages setObject:texture forKey:imageToLoad];
        toReturn = texture;
    }

    [self.dictionaryModificationLock unlock]; // unlock the NSLock
    return toReturn;
}

崩溃报告如下所示:

Fatal Exception: NSGenericException
*** Collection <NSConcreteMapTable: 0x1c059ff0> was mutated while being enumerated.

0   CoreFoundation  __exceptionPreprocess + 126
2   CoreFoundation  -[NSException name]
3   Foundation  -[NSConcreteMapTable countByEnumeratingWithState:objects:count:] + 56
4   CoreFoundation  -[__NSFastEnumerationEnumerator nextObject] + 110
5   SpriteKit   +[SKTextureAtlas(Internal) findTextureNamed:] + 284
6   SpriteKit   __26-[SKTexture loadImageData]_block_invoke + 1654
7   SpriteKit   SKSpinLockSync(int*, void () block_pointer) + 104
8   SpriteKit   -[SKTexture loadImageData] + 302
9   SpriteKit   -[SKTexture size] + 42

我发现其他一些帖子说这是 SpriteKit 的问题。但我认为必须有一些解决方法。大家怎么看?

谢谢,

加伦

这是一个错误

这绝对像是 SpriteKit 中的错误。您可以尝试先预加载图像,它可能会在单独的代码路径下结束。它可能的预加载将有助于防止这种情况发生。

https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Sprites/Sprites.html#//apple_ref/doc/uid/TP40013043-CH9-SW21

图集

如果您还没有这样做,请考虑使用纹理图集并在其中预加载所有资产。

https://developer.apple.com/library/ios/documentation/GraphicsAnimation/Conceptual/SpriteKit_PG/Sprites/Sprites.html#//apple_ref/doc/uid/TP40013043-CH9-SW15

锁定

旁注,我认为这根本不会解决您的崩溃问题,但是使用@synchronized 进行锁定更具语义。

不是使用 NSLock,而是将当前锁代码包装在 @synchronized(self) 中。如果您与代码的其他部分发生争用也锁定了自己,那么您可以创建一个单独的 id textureLockObject 属性.

Apple 可以并且将会比使用 NSLocks 更优化@synchronized 代码。

https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html#//apple_ref/doc/uid/10000057i-CH8-SW3