dam*_*hec 8 multithreading ios sprite-kit sktextureatlas
我在预加载时遇到了性能损失SKTextureAtlas:
let textureAtlas = SKTextureAtlas(named: atlasName)
textureAtlas.preload(completionHandler: {
...
})
Run Code Online (Sandbox Code Playgroud)
通过性能命中,我的意思是FPS在短时间内降至~50.
我测试了它Time Profiler在Instruments和验证,这项工作确实正在上一个工人线程中完成,就像在声明文件.
图像波纹显示了Time Profiler由预加载图集引起的尖峰捕获.正如您所看到的,大多数峰值是由2个工作线程引起的,据我所知,这些线程似乎都在加载图像数据.但是,这不应该导致主线程IMHO的性能损失.
注1:.spriteatlas我预加载不是那么大:4个资产大约.1000x1000尺寸.
注2:我正在测试iPhone 6,iOS 10,Xcode 8.
注3:同时没有其他实质性工作; CPU一直徘徊在~30%左右.GPU也是如此.
注4:在需要来自该图集的任何纹理之前,请求图集预加载,因此它应该有足够的时间来预加载.
任何帮助/方向非常感谢!
UPDATE
发生预加载的完整代码块:
let updateGroup = DispatchGroup()
for assetDefinition in assetContainmentDefinitions {
let assetName = assetDefinition.assetName
// Check if asset is not needed anymore and clear the cache with it
if progress >= assetDefinition.range.to {
if cachedAssets[assetName] != nil {
cachedAssets[assetName] = nil
}
}
// Check if asset is needed and if it's not already loading then preload and cache it
else if progress >= assetDefinition.range.from {
if currentlyLoadingAssets.contains(assetName) == false &&
cachedAssets[assetName] == nil {
currentlyLoadingAssets.append(assetName)
// Enter dispatch group
updateGroup.enter()
switch assetDefinition.assetType {
case .textureAtlas:
let textureAtlas = SKTextureAtlas(named: assetName)
textureAtlas.preload(completionHandler: {
DispatchQueue.main.async { [weak self] in
self?.cachedAssets[assetName] = textureAtlas
self?.currentlyLoadingAssets.remove(object: assetName)
// Leave dispatch group after preload is done
updateGroup.leave()
}
})
case .texture:
let texture = SKTexture(imageNamed: assetName)
texture.preload(completionHandler: {
DispatchQueue.main.async { [weak self] in
self?.cachedAssets[assetName] = texture
self?.currentlyLoadingAssets.remove(object: assetName)
// Leave dispatch group after preload is done
updateGroup.leave()
}
})
}
}
}
}
// Call completion after the dispatch group is fully completed
if let completion = completion {
updateGroup.notify(queue: DispatchQueue.main, execute: completion)
}
Run Code Online (Sandbox Code Playgroud)
更新2
我创建了一个空项目,只有atlas预加载块.性能下降仍然存在.我尝试过多个地图集,即使是只有一个资产的地图集.
在这个空的新项目中,我也尝试了@Sez建议(参见下文),但在这种情况下,甚至没有调用完成块,这似乎是类中的另一个错误SKTextureAtlas.(?!)
let atlas = SKTextureAtlas(dictionary: ["texture1": UIImage(named: "texture1")!])
atlas.preload(completionHandler: { [weak self] in
print("COMPLETION BLOCK NOT CALLED")
self?.cachedAtlas = atlas
})
Run Code Online (Sandbox Code Playgroud)
更新3
我尝试删除.spriteatlas并.atlas使用相同的纹理创建,并且(几乎)没有性能命中.但是,.atlas不支持切片,这就是我想首先使用的原因.spriteatlas.
存在困扰SKTextureAtlas(Apple Dev论坛帖子)的问题.
尝试使用SKTextureAtlas:withDictionary:提供另一个StackOverflow帖子中描述[String:UIImage]的方法的字典创建纹理图集,看看是否有帮助.
更新:如果你想在后台线程中发生SKTexture的预加载,我会专门写一下而不是依赖于preload便利功能.
let atlas: SKTextureAtlas
let myImages: [String: UIImage] = getImages()
let globalQueue = DispatchQueue.global()
globalQueue.async {
let atlas = SKTextureAtlas(withDictionary:myImages)
for (k,v) in myImages {
let tex = atlas.textureNamed(k)
print(tex.size()) // force load
}
DispatchQueue.main.async {
completionHandler(atlas)
}
}
Run Code Online (Sandbox Code Playgroud)
关于应用程序切片,只要您将资产放在资产目录中,就应该对它们进行切片.将构建上传到iTunesConnect后,您可以看到反映此内容的App Store大小的报告.
我有一个视频,我记录了一个实时流,我显示了这个导入过程.对不起它有点令人痛苦的长(2小时+),但这里的链接正好进入精灵表的导入.
https://youtu.be/Ic9Wnux8vd8?t=1h17m
按照我在这里展示的方式进行操作,你会得到一个精灵图册,带有切片图像.如果你想要的话,我的脚本(我在前面的剪辑中演示过)就在我的GitHub上.