调用函数时App卡顿无调试日志,Firebase数据存入结构体数组问题求助
问题原因
- 核心卡死原因:你写的
while keys < 6是同步阻塞在主线程的逻辑,而Firebase的addSnapshotListener属于异步回调,必须等主线程空闲时才会执行回调内的代码。现在主线程一直跑while死循环,永远没空执行Firebase的回调,keys永远不会被更新,直接卡死主线程,所以出现APP卡顿、控制台无日志输出的问题。 - 额外逻辑漏洞:你一共只有5个字段需要读取,就算全部读取成功
keys最多也只能到5,永远达不到6,哪怕Firebase回调能执行,while循环也永远不会停止。同时你循环使用的区间是0...count,会多循环一次导致数组越界崩溃,且同一个对象重复追加了两次到数组,属于无效逻辑。
修复后的代码
// 提前定义统一的模型,后续维护更方便 struct Restaurant: Identifiable { let id: String let name: String let imageUrl: URL let rating: Double let url: URL } db.collection("parties").document(Utilities.code).addSnapshotListener { document, error in // 优先处理错误和空值情况 if let error = error { print("error = \(error)") return } guard let document = document, document.exists else { print("文档不存在") return } // 统一读取所有字段,同时校验长度一致避免越界 guard let names = document.get("yesName") as? [String], let imageUrls = document.get("yesImg") as? [String], let ids = document.get("yesId") as? [String], let ratings = document.get("yesRating") as? [Double], let urls = document.get("yesUrl") as? [String], names.count == imageUrls.count, names.count == ids.count, names.count == ratings.count, names.count == urls.count else { print("字段格式不匹配") return } // 直接组装数组,不需要额外的while循环等待 var tempList = [RestaurantListViewModel]() for i in 0..<names.count { guard let imageUrl = URL(string: imageUrls[i]), let linkUrl = URL(string: urls[i]) else { continue } let vm = RestaurantListViewModel( name: names[i], imageUrl: imageUrl, id: ids[i], rating: ratings[i], url: linkUrl ) tempList.append(vm) } // 更新UI请确保在主队列执行 DispatchQueue.main.async { yes.list = tempList } }
更优的存储方案
- 不要把同一个对象的不同属性拆成多个独立数组存储,统一存为对应模型的数组,避免出现数组长度不一致导致的越界问题,维护成本更低。
- 可以调整Firebase的文档结构,直接存储餐厅对象的嵌套数组,无需拆成5个独立数组,后续可以直接用Firebase自带的Codable解码能力一键解析,不需要手动逐个取字段,代码更简洁出错概率更低。
内容的提问来源于stack exchange,提问作者Mcrich
相关产品推荐
相关产品推荐

