从Core Data加载SKTexture数组时性能不佳的问题排查
解决SpriteKit动画加载延迟的优化方案
核心问题分析
你当前的代码在主线程同步执行SKTexture(image: UIImage(data: ...))的转换操作,多帧场景下会阻塞UI线程,直接导致SwiftUI视图加载时出现1-2秒的延迟。
具体优化方案
1. 后台异步预加载纹理
把纹理加载逻辑放到全局后台队列执行,避免阻塞主线程。加载完成后回到主线程缓存结果,还可通过批量预加载进一步优化渲染性能:
func preloadAnimationTextures(for frames: [AnimationFrame], completion: @escaping ([SKTexture]) -> Void) { DispatchQueue.global(qos: .userInitiated).async { var textures = [SKTexture]() for frame in frames { guard let data = frame.imageData, let image = UIImage(data: data) else { continue // 处理错误,避免强制解包崩溃 } textures.append(SKTexture(image: image)) } // 批量预加载纹理,提前完成GPU层面的准备 SKTexture.preload(textures) { DispatchQueue.main.async { completion(textures) } } } }
2. 实现纹理缓存机制
用单例类缓存已加载的纹理,根据动画的唯一标识(比如Core Data实体的objectID)存储,避免重复加载:
class TextureCache { static let shared = TextureCache() private var cache = [NSManagedObjectID: [SKTexture]]() func store(textures: [SKTexture], for animationID: NSManagedObjectID) { cache[animationID] = textures } func retrieve(for animationID: NSManagedObjectID) -> [SKTexture]? { return cache[animationID] } }
3. 预判用户操作触发预加载
在用户可能打开动画的前置场景提前触发预加载:
- 比如用户进入动画列表页时,加载列表中前几个动画的纹理
- 或者检测到用户滑动到某个动画条目、长按条目时,触发对应动画的纹理预加载
示例:SwiftUI列表中,条目出现时触发预加载
struct AnimationList: View { let animations: [Animation] var body: some View { List(animations) { animation in AnimationRow(animation: animation) .onAppear { guard TextureCache.shared.retrieve(for: animation.objectID) == nil else { return } let sortedFrames = animation.frames.sorted(by: { $0.order < $1.order }) preloadAnimationTextures(for: sortedFrames) { textures in TextureCache.shared.store(textures: textures, for: animation.objectID) } } } } }
4. SwiftUI视图中使用预加载纹理
用户打开动画视图时,直接从缓存取纹理,无缓存时显示加载状态并兜底触发加载:
struct AnimationPlayerView: View { let animation: Animation var body: some View { Group { if let textures = TextureCache.shared.retrieve(for: animation.objectID) { SpriteView(scene: AnimationScene(textures: textures)) } else { ProgressView("加载中...") .onAppear { let sortedFrames = animation.frames.sorted(by: { $0.order < $1.order }) preloadAnimationTextures(for: sortedFrames) { textures in TextureCache.shared.store(textures: textures, for: animation.objectID) } } } } } }
额外优化点
- 移除强制解包:替换代码中的
!,处理可选值避免崩溃 - 内存管控:收到内存警告时,清空部分不常用的缓存内容
- 优先级调整:用
.userInitiated队列优先级,保证预加载任务优先执行
内容的提问来源于stack exchange,提问作者whaleshark
相关产品推荐
相关产品推荐

