在 Swift 6 中预加载 SKTextureAtlas 时崩溃

问题描述 投票:0回答:1

我有以下代码:

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

我已经尝试过:

  • 使用 Swift 5,并进行严格的并发检查。没有崩溃,没有警告。
  • 保留 Swift 6,但删除
    preload
    调用。没有崩溃。然而,出于游戏过程中性能的原因,我需要这个
    preload

我不知道为什么它会在这里崩溃。堆栈跟踪是汇编代码。

ios swift sprite-kit
1个回答
0
投票

仅从崩溃报告来看,这似乎是 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
做同样的事情。

© www.soinside.com 2019 - 2024. All rights reserved.