SwiftData异步导入数据时随机触发EXC_BAD_ACCESS问题求助
SwiftData异步导入交易数据时随机触发EXC_BAD_ACCESS问题排查
问题概述
使用SwiftData构建一对多关系(Transaction与Category),异步导入文本文件中的交易数据时,随机触发EXC_BAD_ACCESS错误。崩溃位置固定在设置Transaction的category属性时,但崩溃时机和涉及的交易数据不固定。已使用async/await异步加载数据,通过MainActor更新进度条,借助actor插入交易数据;尝试过Address Sanitizer、Thread Sanitizer和Zombie objects工具调试,未定位到问题根源,怀疑是关系设置错误、数据竞争或内存问题。
相关代码
模型定义代码
@Model class Transaction: Hashable { @Attribute(.unique) let id = UUID().uuidString var date = Date() //... 其他属性 // @Relationship(inverse: \Category.transactions) var category: Category? init(date: Date = Date(), balance: Double = 0.0, category: Category) { self.date = date self.balance = balance self.category = category // <-- 崩溃位置,已确认category地址有效 category.add(transaction: self) } } @Model class Category { @Attribute(.unique) let id = UUID().uuidString var name: String? //... 其他属性 @Relationship(deleteRule: .cascade, inverse: \Transaction.category) var transactions: [Transaction]? = [] init(name: String? = nil) { self.name = name } func add(transaction: Transaction) { if var transactions = self.transactions { transactions.append(transaction) } } }
文件读取与数据创建代码
private func readFile(data: String) async { //... 解析文本行逻辑 // 创建Transaction时触发问题 let t = Transaction(date: date, category: category) transactions.append(t) } // 批量插入逻辑 await actor.insert(category) // 读取完成后插入Category
崩溃指向的SwiftData内部代码
{ // @Relationship(inverse: \Category.transactions) @storageRestrictions(accesses: _$backingData, initializes: _category) init(initialValue) { _$backingData.setValue(forKey: \.category, to: initialValue) _asset = _SwiftDataNoType() } // @Relationship(inverse: \Category.transactions) get { _$observationRegistrar.access(self, keyPath: \.category) return self.getValue(forKey: \.category) } // @Relationship(inverse: \Category.transactions) set { _$observationRegistrar.withMutation(of: self, keyPath: \.category) { self.setValue(forKey: \.category, to: newValue) <---- SwiftData内部崩溃位置 } } }
最终崩溃点代码
@main struct DataImportWithProgressViewApp: App { <---- 崩溃点:Thread1: EXC_BAD_ACCESS (code=1, address=0x8000000000000010) let container = try! ModelContainer( for: Category.self ) var body: some Scene { WindowGroup { ContentView() } .modelContainer(container) } }
排查方向与解决方案
- 修复关系定义缺失:取消Transaction类中
@Relationship(inverse: \Category.transactions)的注释,SwiftData需要明确的双向关系定义来正确管理对象关联,缺失反向关联会导致框架内部状态混乱。 - 移除手动维护关联的代码:删除Transaction初始化方法中的
category.add(transaction: self)调用,SwiftData会自动维护Category的transactions数组,手动修改会破坏框架的内部状态一致性,引发内存访问错误。 - 确保模型对象在正确上下文创建:所有SwiftData模型对象的创建和修改必须在ModelContext所在的Actor上下文执行。如果使用自定义actor处理数据插入,需确保Transaction和Category的创建也在该Actor中完成,避免跨Actor访问未托管的模型对象。
- 修正ModelContainer初始化:当前ModelContainer仅注册了Category,需同时包含Transaction,否则框架无法正确加载Transaction的模型元数据,导致关系处理失败。修改代码如下:
let container = try! ModelContainer( for: Category.self, Transaction.self ) - 优化批量插入逻辑:避免先创建大量未托管的模型对象再批量插入,建议在解析每条交易数据时,直接通过ModelContext的
insert(_:)方法将对象插入上下文,确保模型对象始终处于框架的托管状态。
内容的提问来源于stack exchange,提问作者RXP
相关产品推荐
相关产品推荐

