You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Firestore中QuerySnapshot运行报错:GRPC_LINUX_EPOLL未定义

问题分析与解决方案

首先要明确:你看到的 "Skipping epollsig becuase GRPC_LINUX_EPOLL is not defined" 并不是代码错误,它只是GRPC库(Firebase依赖的底层网络库)的调试日志输出,和你打印字段的次数只是巧合关联,完全可以忽略,或者在Xcode日志过滤器中屏蔽这条日志。

真正需要修正的是你的数据解析、打印逻辑,以及随机文档查询的实现,下面逐一说明:

1. 模型类的问题:强制解包风险 + 打印无意义内容

你当前的randomModel类存在两个问题:

  • 用!强制解包Firestore字段值,如果字段缺失、类型不匹配,会直接导致崩溃
  • 没有实现CustomStringConvertible,直接打印模型数组只会输出对象内存地址,看不到实际数据

修改后的模型类

// 类名首字母大写符合Swift命名规范
class RandomModel {
    private(set) var quote: String
    private(set) var randomInt: Int
    private(set) var approved: Bool
    private(set) var source: String
    
    init(approved: Bool, quote: String, randomInt: Int, source: String) {
        self.approved = approved
        self.quote = quote
        self.randomInt = randomInt
        self.source = source
    }
    
    class func parseData(snapshot: QuerySnapshot?) -> [RandomModel] {
        var quoteStructure = [RandomModel]()
        guard let snap = snapshot else { return quoteStructure }
        
        for document in snap.documents {
            let data = document.data()
            // 用可选绑定安全获取字段值,无效文档直接跳过
            guard let quote = data[DATABASE_QUOTE_VALUE_FIELD] as? String,
                  let randomInt = data[DATABASE_RANDOM_INTEGER_VALUE_FIELD] as? Int,
                  let approved = data[DATABASE_APPROVED_VALUE_FIELD] as? Bool,
                  let source = data[DATABASE_SOURCE_VALUE_FIELD] as? String else {
                debugPrint("跳过无效文档:\(document.documentID),字段缺失或类型不匹配")
                continue
            }
            
            let parsedData = RandomModel(approved: approved, quote: quote, randomInt: randomInt, source: source)
            quoteStructure.append(parsedData)
        }
        return quoteStructure
    }
}

// 实现CustomStringConvertible,让打印时显示实际字段内容
extension RandomModel: CustomStringConvertible {
    var description: String {
        return "RandomModel(quote: \"\(quote)\", randomInt: \(randomInt), approved: \(approved), source: \"\(source)\")"
    }
}

2. 随机文档查询逻辑错误

你当前的查询whereField(DATABASE_RANDOM_INTEGER_VALUE_FIELD, isGreaterThan: 1).order(by: "randomInt").limit(to: 1)并不是真正的随机,它每次都会取randomInt大于1的第一个文档,结果是固定的。

修正后的随机查询实现

这个方案通过先获取集合中randomInt的最大值,生成一个随机数,再查询对应区间的文档,确保每次返回随机结果:

@IBAction func generatePressed(_ sender: Any) {
    let quoteRef = Firestore.firestore().collection("Quotes")
    
    // 第一步:获取集合中最大的randomInt值
    quoteRef.order(by: DATABASE_RANDOM_INTEGER_VALUE_FIELD, descending: true).limit(to: 1).getDocument { (docSnapshot, error) in
        if let err = error {
            debugPrint("获取max randomInt失败:\(err)")
            return
        }
        
        guard let maxRandomInt = docSnapshot?.data()?[DATABASE_RANDOM_INTEGER_VALUE_FIELD] as? Int else {
            debugPrint("无法获取max randomInt")
            return
        }
        
        // 生成1到maxRandomInt之间的随机数
        let randomValue = Int.random(in: 1...maxRandomInt)
        
        // 第二步:查询大于等于随机数的第一个文档
        let query = quoteRef.whereField(DATABASE_RANDOM_INTEGER_VALUE_FIELD, isGreaterThanOrEqualTo: randomValue)
            .order(by: DATABASE_RANDOM_INTEGER_VALUE_FIELD)
            .limit(to: 1)
        
        query.getDocument { (snapshot, error) in
            if let err = error {
                debugPrint("获取随机文档失败:\(err)")
                return
            }
            
            // 如果没找到, fallback到查询小于随机数的最后一个文档(处理随机数是最大值的情况)
            if snapshot == nil || snapshot?.exists == false {
                let fallbackQuery = quoteRef.whereField(DATABASE_RANDOM_INTEGER_VALUE_FIELD, isLessThan: randomValue)
                    .order(by: DATABASE_RANDOM_INTEGER_VALUE_FIELD, descending: true)
                    .limit(to: 1)
                
                fallbackQuery.getDocument { (fallbackSnapshot, fallbackError) in
                    if let err = fallbackError {
                        debugPrint("获取备选随机文档失败:\(err)")
                        return
                    }
                    
                    // 解析并打印数据
                    if let fallbackSnap = fallbackSnapshot {
                        let querySnapshot = QuerySnapshot(documents: [fallbackSnap], metadata: SnapshotMetadata())
                        let models = RandomModel.parseData(snapshot: querySnapshot)
                        print(models)
                    }
                }
            } else {
                // 解析并打印数据
                if let snap = snapshot {
                    let querySnapshot = QuerySnapshot(documents: [snap], metadata: SnapshotMetadata())
                    let models = RandomModel.parseData(snapshot: querySnapshot)
                    print(models)
                }
            }
        }
    }
}

3. 额外说明

  • 如果你的randomInt字段是在文档创建时生成的随机数,确保它的取值范围覆盖所有文档,这样随机查询的效果才会均匀
  • 如果你不需要实时监听文档变化,用getDocument替代addSnapshotListener更合适,避免不必要的实时更新监听

内容的提问来源于stack exchange,提问作者TVProducer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:48:00