8

プリロード時にパフォーマンス ヒットが発生していますSKTextureAtlas

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

パフォーマンス ヒットとは、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 : アトラスのプリロードは、そのアトラスのテクスチャが必要になる前に要求されるため、プリロードするのに十分な時間が必要です。

どんな助け/指示も大歓迎です!


アップデート

プリロードが発生する完全なコード ブロック:

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

アトラスプリロードブロックだけで空のプロジェクトを作成しました。パフォーマンスの低下は引き続き発生します。アセットが 1 つしかないアトラスでも、複数のアトラスを試してみました。

この空の新しいプロジェクトで@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 フォーラムの投稿)。

別の StackOverflow 投稿で説明されている方法SKTextureAtlas:withDictionary:ある のディクショナリを提供することを使用してテクスチャ アトラスを作成し、それが役立つかどうかを確認してください。[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 に答える