枚举时加载 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 中的错误。您可以尝试先预加载图像,它可能会在单独的代码路径下结束。它可能的预加载将有助于防止这种情况发生。
图集
如果您还没有这样做,请考虑使用纹理图集并在其中预加载所有资产。
锁定
旁注,我认为这根本不会解决您的崩溃问题,但是使用@synchronized 进行锁定更具语义。
不是使用 NSLock,而是将当前锁代码包装在 @synchronized(self)
中。如果您与代码的其他部分发生争用也锁定了自己,那么您可以创建一个单独的 id textureLockObject
属性.
Apple 可以并且将会比使用 NSLocks 更优化@synchronized 代码。
我在使用以下代码时遇到问题,该代码通过调用 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 中的错误。您可以尝试先预加载图像,它可能会在单独的代码路径下结束。它可能的预加载将有助于防止这种情况发生。
图集
如果您还没有这样做,请考虑使用纹理图集并在其中预加载所有资产。
锁定
旁注,我认为这根本不会解决您的崩溃问题,但是使用@synchronized 进行锁定更具语义。
不是使用 NSLock,而是将当前锁代码包装在 @synchronized(self)
中。如果您与代码的其他部分发生争用也锁定了自己,那么您可以创建一个单独的 id textureLockObject
属性.
Apple 可以并且将会比使用 NSLocks 更优化@synchronized 代码。