Xcode14.3+Firebase9.6.0映射Firestore文档时遇无参数调用错误
Firestore文档映射自定义Codable结构体时编译错误问题(Xcode14.3 + Firebase9.6.0)
使用Xcode14.3、Firebase9.6.0开发时,尝试将Firestore文档映射到实现了Identifiable、Codable协议的自定义Game结构体,遵循Firebase官方编码指南后仍遇到以下问题:
- 第一种写法虽提示「Arguments passed to call takes no arguments」错误,但可正常编译运行;
- 第二种优化写法(包含细分错误处理逻辑)却无法通过编译。
Game结构体定义
struct Game: Identifiable, Codable { @DocumentID var id: String? // Firestore文档UUID var nr: Int? var status: String? var league: String var homeTeam: String var homeTeamLogoUrl: String? var guestTeam: String var guestTeamLogoUrl: String? var runs: Runs? var scheduledDate: Date var startTime: Date? var endTime: Date? var ballpark: String var city: String var scorerID: String? var score: Count? var bases: BaseStatus? var inning: Int? var inningHalf: String? var inningResults: [InningResult]? }
两种写法对比
第一种:报错但可运行的代码
func getLiveGames(country: String, league: String, season: Int) async { // 声明临时直播赛事列表 var liveGames = [Game]() let leagueRef = db.collection("liveGames") let snapshot = try? await leagueRef.getDocuments() if snapshot != nil { for docs in snapshot!.documents { do { let result = try docs.data(as: Game.self) print(result) } catch { print(error) } } } else { self.errorMessage = "No documents in 'liveGames' collection" print(self.errorMessage) } }
第二种:无法编译的代码
func getLiveGames(country: String, league: String, season: Int) async { // 声明临时直播赛事列表 var liveGames = [Game]() let leagueRef = db.collection("liveGames") let queryLiveGames = try? await leagueRef.getDocuments() if queryLiveGames != nil { liveGames = (queryLiveGames!.documents.compactMap({ (queryDocumentSnapshot) -> Game? in let result = Result { try? queryDocumentSnapshot.data(as: Game.self) } switch result { case .success(let game): if var game = game { // 从DocumentSnapshot成功初始化Game实例 self?.errorMessage = nil liveGames.append(game) return game } else { // DocumentSnapshot为nil或初始化出nil值 self.errorMessage = "Game document doesn't exist." return nil } case .failure(let error): // 无法从DocumentSnapshot初始化Game实例 switch error { case DecodingError.typeMismatch(_, let context): self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)" case DecodingError.valueNotFound(_, let context): self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)" case DecodingError.keyNotFound(_, let context): self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)" case DecodingError.dataCorrupted(let key): self.errorMessage = "\(error.localizedDescription): \(key)" default: self.errorMessage = "Error decoding document: \(error.localizedDescription)" } return nil } })) } else { self.errorMessage = "No documents in 'liveGames' collection" print(self.errorMessage) } }
问题原因与修正方案
问题分析
- 第一种写法的报错:属于Xcode编辑器的语法检测误报,Firebase的
data(as:)方法在Swift并发环境下偶尔会触发编辑器签名识别bug,实际编译时能正确解析方法,因此可以正常运行。 - 第二种写法的编译失败:
- 逻辑冲突:在
compactMap中同时执行liveGames.append(game)和将compactMap返回值赋值给liveGames,导致重复操作且编译器类型推断混乱; Result类型错误:try? queryDocumentSnapshot.data(as: Game.self)返回Game?,导致Result类型为Result<Game?, Error>,后续switch分支的类型处理出现歧义;self可选性错误:若当前函数属于非可选类型的实例,self不需要加?,这会直接导致编译报错。
- 逻辑冲突:在
修正后的可编译代码
func getLiveGames(country: String, league: String, season: Int) async { var liveGames = [Game]() let leagueRef = db.collection("liveGames") // 先判断快照是否存在,避免强制解包 guard let queryLiveGames = try? await leagueRef.getDocuments() else { self.errorMessage = "No documents in 'liveGames' collection" print(self.errorMessage) return } // 用compactMap直接构建结果数组,移除内部append操作 liveGames = queryLiveGames.documents.compactMap { document -> Game? in do { let game = try document.data(as: Game.self) self.errorMessage = nil return game } catch { // 细分解码错误处理 switch error { case DecodingError.typeMismatch(_, let context): self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)" case DecodingError.valueNotFound(_, let context): self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)" case DecodingError.keyNotFound(_, let context): self.errorMessage = "\(error.localizedDescription): \(context.debugDescription)" case DecodingError.dataCorrupted(let key): self.errorMessage = "\(error.localizedDescription): \(key)" default: self.errorMessage = "Error decoding document: \(error.localizedDescription)" } return nil } } // 此处可添加liveGames的后续业务逻辑 }
内容的提问来源于stack exchange,提问作者Peter Luger
相关产品推荐
相关产品推荐

