我们已经收到了崩溃报告,其中包括短语“suspend resume partial function”,这似乎来自我们使用Swift并发。堆栈跟踪的一个示例是
Crashed: com.apple.root.user-initiated-qos.cooperative
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000cf855c2e0
0 libobjc.A.dylib 0x4174 objc_release + 16
1 libobjc.A.dylib 0x4174 objc_release_x0 + 16
2 libswiftCore.dylib 0x3ad2c8 swift_arrayDestroy + 124
3 libswiftCore.dylib 0x98f38 _ContiguousArrayStorage.__deallocating_deinit + 96
4 libswiftCore.dylib 0x3bd628 _swift_release_dealloc + 56
5 libswiftCore.dylib 0x3be44c bool swift::RefCounts<swift::RefCountBitsT<(swift::RefCountInlinedness)1> >::doDecrementSlow<(swift::PerformDeinit)1>(swift::RefCountBitsT<(swift::RefCountInlinedness)1>, unsigned int) + 132
6 MyAppName 0x32e08c (3) suspend resume partial function for ProductUpdater.updateProducts() + 138 (Products.swift:138)
7 libswift_Concurrency.dylib 0x41948 swift::runJobInEstablishedExecutorContext(swift::Job*) + 416
8 libswift_Concurrency.dylib 0x42868 swift_job_runImpl(swift::Job*, swift::ExecutorRef) + 72
9 libdispatch.dylib 0x15944 _dispatch_root_queue_drain + 396
10 libdispatch.dylib 0x16158 _dispatch_worker_thread2 + 164
11 libsystem_pthread.dylib 0xda0 _pthread_wqthread + 228
12 libsystem_pthread.dylib 0xb7c start_wqthread + 8
Crashlytics似乎认为call 6是这里的问题,它将崩溃标记为“(3)suspend resume partial function for ProductUpdater.updateProducts()”。
短语“suspend resume partial function”是什么意思,它表示程序正在做什么导致了问题?下面是代码相关部分的一个非常粗略的草图:
struct Product: Codable, Equatable {
var id: String
var name: String
var price: Int
}
struct ProductWrapper: Codable, Equatable {
var metadata: String
var products: [Product]
static let none = ProductWrapper(metadata: "none", products: [])
}
class ProductUpdater {
var userIsSignedIn: Bool = false
var products: ProductWrapper = .none
init() {
Task {
await updateProducts()
}
}
private func updateProducts() async {
// If there's no user signed in, we can't fetch the products.
guard userIsSignedIn else {
products = .none
return
}
do {
// This next line was line 138 in the original code:
products = try await NetworkService.fetchProducts()
} catch {
print("Could not fetch products: \(error)")
}
}
}
根据这篇关于GitHub问题的评论中的模糊建议,我试图将products
的赋值 Package 在一个看似毫无意义的延续中,
private func updateProducts() async {
// If there's no user signed in, we can't fetch the products.
guard userIsSignedIn else {
products = .none
return
}
do {
let updatedProducts = try await NetworkService.fetchProducts()
await withCheckedContinuation { continuation in
products = updatedProducts
continuation.resume()
}
} catch {
print("Could not fetch products: \(error)")
}
}
但这似乎并没有解决问题。
我们使用Xcode Cloud来生成我们的构建,它使用的是Xcode 14.3.1(Swift 5.8.1)。
1条答案
按热度按时间9bfwbjaz1#
“suspend resume partial function”表示任务在
await
之后恢复。部分函数是两个await
调用之间的函数部分(或函数的开始或结束)。此崩溃是由于阵列上的过度释放。我希望您是在多个线程上访问
products
(或改变ProductWrapper的任何部分)。我不明白这段代码是如何编译的。
init
返回时未初始化products
,这是无效的。也许你正在跳过一个编译器错误。您需要确保在返回之前初始化所有属性。您还通过随机线程上的任务修改产品,这是无效的。
我相信您希望进行以下更改:
你可能想让ProductUpdater成为MainActor:
这将确保您对
products
的访问和修改是以原子方式完成的(它也会将init
中的Task推送到主actor上)。如果你想让它在另一个线程上,你几乎肯定应该让它成为一个普通的actor而不是一个类。如果这仍然是一个问题,您需要为
products
添加某种锁定,以便它不会在多个线程上被访问。我鼓励在你的方案中打开线程消毒器(在诊断下),看看是否还有其他地方有这个问题。