我有以下代码:
import UIKit
import SpriteKit
class ViewController: UIViewController {
let textureAtlas: SKTextureAtlas
required init?(coder: NSCoder) {
textureAtlas = SKTextureAtlas(dictionary: ["Foo": UIImage(named: "foo.png")!])
super.init(coder: coder)
textureAtlas.preload {
}
}
}
您可以将随机
foo.png
文件添加到您的项目中。然后用 Swift 6 模式运行会崩溃:
Thread 4 Queue : com.apple.spritekit.preloadQueue (concurrent)
#0 0x00000001099476f5 in _dispatch_assert_queue_fail ()
#1 0x000000010994768f in dispatch_assert_queue ()
#2 0x00007ffc10f5f251 in swift_task_isCurrentExecutorImpl ()
#3 0x0000000109e05f39 in closure #1 in ViewController.init(coder:) ()
#4 0x0000000109e05fa8 in thunk for @escaping @callee_guaranteed () -> () ()
#5 0x0000000109944b3d in _dispatch_call_block_and_release ()
#6 0x0000000109945ec6 in _dispatch_client_callout ()
#7 0x00000001099490f3 in _dispatch_continuation_pop ()
#8 0x0000000109947f20 in _dispatch_async_redirect_invoke ()
#9 0x0000000109959d2c in _dispatch_root_queue_drain ()
#10 0x000000010995a8ef in _dispatch_worker_thread2 ()
#11 0x00000001093c4b43 in _pthread_wqthread ()
#12 0x00000001093c3acf in start_wqthread ()
Enqueued from com.apple.spritekit.preloadQueue (Thread 4) Queue : com.apple.spritekit.preloadQueue (serial)
#0 0x0000000109946bf1 in _dispatch_group_wake ()
#1 0x0000000109949239 in _dispatch_continuation_pop ()
#2 0x0000000109947f20 in _dispatch_async_redirect_invoke ()
#3 0x0000000109959d2c in _dispatch_root_queue_drain ()
#4 0x000000010995a8ef in _dispatch_worker_thread2 ()
#5 0x00000001093c4b43 in _pthread_wqthread ()
#6 0x00000001093c3acf in start_wqthread ()
我已经尝试过:
preload
调用。没有崩溃。然而,出于游戏过程中性能的原因,我需要这个preload
。我不知道为什么它会在这里崩溃。堆栈跟踪是汇编代码。
仅从崩溃报告来看,这似乎是 SpriteKit 中的一个错误。完成处理程序闭包在队列上被调用
com.apple.spritekit.preloadQueue
,但 Swift Concurrency 不知道这一点。
Swift Concurrency 假设闭包将在与调用
preload
相同的并发上下文中调用,因为闭包未标记为 @Sendable
。
大概 Swift 6 编译器会在闭包开始处插入一个检查,以检查它是否在正确的并发上下文中运行(跟踪中的
swift_task_isCurrentExecutorImpl
行),但在 Swift 5 模式下,此检查要么不会不存在,或者它被设计为不会崩溃以匹配之前的行为。
标记关闭
@Sendable
修复了崩溃问题。
textureAtlas.preload { @Sendable in
}
似乎 Objective-C API 中的其他完成处理程序都标记为
@Sendable
,例如 AVAsset.loadTracks
、URLSession.dataTask
等。SpriteKit 团队可能忘记对 preload
做同样的事情。