KMM项目iOS端无法获取Kotlin仓库数据,报EXC_BAD_ACCESS错误求助
KMM项目iOS端获取数据抛出EXC_BAD_ACCESS异常排查与解决
问题背景
Kotlin端可正常获取数据,但iOS端调用时抛出异常:Thread 4: EXC_BAD_ACCESS (code=EXC_I386_GPFLT),崩溃点位于Swift代码的强制类型转换行。
相关代码
Kotlin端仓库代码
suspend fun getRestaurantsOrders(): CommonFlow<List<Order>> { val userId = appService.currentUser!!.id val restaurant = realm.query<Restaurant>("userID = $0", userId).first().find()!! return withContext(Dispatchers.Default) { realm.query<Order>("restaurantID = $0 && totalQuantity > 0 SORT(discount DESC)", restaurant._id.toString()) .asFlow().map { it.list }.asCommonFlow() } }
iOS端Swift调用代码
func getOrdersList() { Task{ do{ try await repo.getRestaurantsOrders().watch(block: {orders in self.restaurantActiveOrdersList = orders as! [Order] //崩溃位置 }) }catch{ print("error") } } }
问题分析与解决方法
1. 强制类型转换不兼容
KMM传递的List<Order>在Swift中对应KotlinList<Order>,而非原生Swift数组[Order],直接用as!强制转换会触发类型不匹配崩溃。
解决:
将Kotlin集合转为Swift原生数组,同时避免强制转换风险:
try await repo.getRestaurantsOrders().watch(block: { orders in // 安全转换后转成Swift数组 guard let kotlinOrders = orders as? KotlinList<Order> else { print("类型转换失败") return } self.restaurantActiveOrdersList = Array(kotlinOrders) })
2. Realm对象线程绑定问题
Realm查询返回的Order是线程绑定的托管对象,Kotlin端用Dispatchers.Default调度后,对象可能在后台线程,iOS端直接访问会触发内存访问异常。
解决:
- 方案一:Kotlin端映射为非托管数据类
将Realm的Order对象映射为普通Kotlin数据类,脱离Realm线程绑定:
// 先定义非托管数据类 data class OrderDto( val id: String, val totalQuantity: Int, val discount: Double, // 其他字段 ) // 修改仓库方法 suspend fun getRestaurantsOrders(): CommonFlow<List<OrderDto>> { val userId = appService.currentUser?.id ?: throw IllegalStateException("用户未登录") val restaurant = realm.query<Restaurant>("userID = $0", userId).first().find() ?: throw IllegalStateException("未找到餐厅") return withContext(Dispatchers.Default) { realm.query<Order>("restaurantID = $0 && totalQuantity > 0 SORT(discount DESC)", restaurant._id.toString()) .asFlow() .map { result -> // 映射为非托管对象 result.list.map { order -> OrderDto( id = order._id.toString(), totalQuantity = order.totalQuantity, discount = order.discount ) } } .asCommonFlow() } }
- 方案二:Swift端确保主线程操作
如果坚持使用Realm对象,需在主线程处理回调结果:
try await repo.getRestaurantsOrders().watch(block: { orders in DispatchQueue.main.async { self.restaurantActiveOrdersList = Array(orders as! KotlinList<Order>) } })
3. Kotlin端强制解包风险
代码中currentUser!!和restaurant!!的强制解包,若为空会抛出未捕获异常,导致iOS端崩溃。
解决:
替换为安全处理,抛出明确异常或返回空:
suspend fun getRestaurantsOrders(): CommonFlow<List<Order>> { val userId = appService.currentUser?.id ?: throw IllegalStateException("当前无登录用户") val restaurant = realm.query<Restaurant>("userID = $0", userId).first().find() ?: throw IllegalStateException("未找到关联餐厅") return withContext(Dispatchers.Default) { realm.query<Order>("restaurantID = $0 && totalQuantity > 0 SORT(discount DESC)", restaurant._id.toString()) .asFlow().map { it.list } .asCommonFlow() } }
内容的提问来源于stack exchange,提问作者user20468094
相关产品推荐
相关产品推荐

