8

我在预加载时遇到了性能问题SKTextureAtlas

let textureAtlas = SKTextureAtlas(named: atlasName)
textureAtlas.preload(completionHandler: {
    ...
})

通过性能打击,我的意思是 FPS 在短时间内下降到约 50。

我用Time Profilerin对其进行了测试,Instruments并验证了这项工作确实是在工作线程上完成的,如文档中所述。

下图显示了Time Profiler由预加载图集引起的尖峰捕获。如您所见,据我所知,大部分峰值是由 2 个工作线程引起的,它们似乎都在加载图像数据。但是,这不应该对主线程恕我直言造成性能影响。

在此处输入图像描述

注 1.spriteatlas我预加载的不是那么大:4 个资产,大约。1000x1000尺寸。

注 2:我正在使用 iPhone 6、iOS 10、Xcode 8 进行测试。

注3:无其他实质性工作同时进行;CPU 一直徘徊在 30% 左右。GPU 也是如此。

注意 4:在需要来自该图集的任何纹理之前请求图集预加载,因此它应该有足够的时间来预加载。

非常感谢任何帮助/方向!


更新

发生预加载的完整代码块:

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)
}

更新 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
})

更新 3

我尝试删除.spriteatlas并创建.atlas具有相同纹理的,并且(几乎)没有性能影响。但是,.atlas不支持切片,这就是我想首先使用.spriteatlas的原因。

4

1 回答 1

6

存在困扰 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)
    }
}

关于应用切片,只要将资产放在资产目录中,它们就应该被切片。将构建上传到 iTunesConnect 后,您可以看到反映这一点的 App Store 大小报告。

iTunesConnect 应用商店规模

我有一个我录制的直播视频,我在其中展示了这个导入过程。抱歉,它的时间有点长(2 小时以上),但这里的链接直接指向精灵表导入发生的那一刻。

https://youtu.be/Ic9Wnux8vd8?t=1h17m

按照我在这里展示的方式进行操作,您将获得一个带有切片图像的精灵图集。如果您需要,我的脚本(我在剪辑的前面演示过)在我的 GitHub 上

于 2016-11-30T06:20:03.233 回答