关于Task.cancel()、deinit调用及Transaction.updates的技术疑问
StoreKit Transaction.updates 相关问题解答
1. 调用updates.cancel()的意义是什么?
- 终止交易监听任务:
Transaction.updates是持续监听StoreKit交易事件的异步序列,调用cancel()会让这个异步迭代器停止等待新事件,直接结束整个后台Task的执行。 - 避免资源浪费:如果不主动取消,即使
TransactionObserver实例已经销毁,这个后台Task可能仍会占用系统资源,持续运行无用的监听逻辑。 - 防止无效回调:当
TransactionObserver实例被销毁后,若交易事件仍触发回调,可能会导致访问已释放资源的问题,取消Task能从根源避免这类意外。
2. 存在对运行中Task的悬空引用且指向self时,deinit()为何仍会被调用?
这个场景里并没有无法打破的循环引用:
当TransactionObserver实例被标记为待销毁时,deinit会优先执行,此时我们调用updates?.cancel(),会触发Transaction.updates异步序列终止迭代,for await循环随即退出,Task的闭包执行完毕,闭包中对self的强引用被释放。同时,updates属性作为实例的一部分,会在deinit执行完成后被销毁,Task实例也失去了唯一引用,最终被系统回收。正是deinit里的取消操作主动打破了潜在的引用循环,让实例能正常销毁。
3. await verificationResult in Transaction.updates挂起时,苹果SDK会检查Task的.isCancelled状态吗?
会的。苹果StoreKit SDK内部针对Transaction.updates异步序列做了处理,当所在Task被取消时,SDK会自动检测到isCancelled状态,立即终止异步迭代,让for await循环退出,不需要开发者手动在挂起点检查取消状态。这是苹果为异步序列提供的内置取消支持,确保任务不会无限挂起。
附原代码
final class TransactionObserver { var updates: Task<Void, Never>? = nil init() { updates = newTransactionListenerTask() } deinit { // Cancel the update handling task when you deinitialize the class. updates?.cancel() } private func newTransactionListenerTask() -> Task<Void, Never> { Task(priority: .background) { for await verificationResult in Transaction.updates { self.handle(updatedTransaction: verificationResult) } } } // [...] }
内容的提问来源于stack exchange,提问作者oxygen
相关产品推荐
相关产品推荐

