【问题标题】:Having trouble loading custom data from firebase using swift使用 swift 从 firebase 加载自定义数据时遇到问题
【发布时间】:2020-02-12 19:14:35
【问题描述】:

我按照 firebase 网站上的指示,想出了下面标记为 NEW CODE 的代码。我得到的错误是:

无法使用类型为“(@escaping () throws -> CombinedModel?)”的参数列表调用类型“Result”的初始化程序

我曾尝试研究 Result 对象和此错误,但没有找到任何可以直接帮助我的东西。我能够使用旧方式(我将在下面发布)读取数据,但我正在尝试遵循 Google 的文档 (https://firebase.google.com/docs/firestore/query-data/get-data)

任何帮助将不胜感激,谢谢!

旧代码

func readData(word: String) -> CombinedModel? {
        print("reading data")
        let docRef = db.collection(K.FBConstants.dictionaryCollectionName).document(word)
        var wordResults: CombinedModel? = nil

        docRef.getDocument { (document, error) in
            if let e = error {
                print("Error loading data: \(e)")
                return
            } else {

                do {
                    if let resultData = try document?.data(as: CombinedModel.self){
                        print("Definitions: \(resultData.definitionsArray)")
                        print("\n Synonyms: \(resultData.synonyms)")
                        wordResults = resultData
                    }
                } catch {
                    print("Error decoding: \(error)")
                }
            }
        }
        return wordResults
    }

新代码

    func newReadData(word: String) -> CombinedModel? {
        let docRef = db.collection(K.FBConstants.dictionaryCollectionName).document(word)

        docRef.getDocument { (document, error) in
            let result = Result {
                try document.flatMap {
                    try $0.data(as: CombinedModel.self)
                }
            }
            switch result {
            case .success(let combinedModel):
                if let combinedModel = combinedModel {
                    print("CombinedModel: \(combinedModel)")
                } else {
                    print("Document does not exist")
                }
            case .failure(let error):
                print("Error decoding city: \(error)")
            }
        }
    }

这是我为读取数据而创建的可编码自定义类。

struct CombinedModel: Codable {
    var definitionsArray: [WordModel]
    var synonyms: [String]

    private enum CodingKeys: String, CodingKey {
        case definitionsArray
        case synonyms
    }
}

struct WordModel: Codable {

    let id: String
    let partOfSpeech: String
    let definitions: [String]
    let example: [String]
    let ipa: String
    let audio: String

    private enum CodingKeys: String, CodingKey {
        case id
        case partOfSpeech
        case definitions
        case example
        case ipa
        case audio
    }
}

struct ThesaurusModel: Codable {

    var synonyms: [String]

    private enum CodingKeys: String, CodingKey {
        case synonyms
    }
}

【问题讨论】:

  • 你为什么要这样做let result = Result?在这个用例中它没有任何用途。为什么这个-> CombinedModel? 作为你的函数不(也不应该)返回任何东西。你能澄清你在这里尝试什么吗?可能有一些方法可以显着简化该代码。
  • 我同意有一些方法可以简化代码。我只是想遵循谷歌关于他们如何推荐阅读自定义对象的文档。如果您点击此链接,您可以看到我在说什么。这对我来说更重要的是试图了解这样做的方法并更好地掌握 swift 5 拥有的新 Result 对象。 firebase.google.com/docs/firestore/query-data/get-data
  • 明白。澄清一下,Firestore 没有自定义对象,因此代码不会读取自定义对象。它正在读取文档(DocumentSnapshot)并将文档字段转换为 your 对象(文档中的 City 对象)。另请注意,文档中的代码不会返回任何内容(因为它不能)。只是想为您节省一些悲伤!
  • 谢谢你的澄清,我边走边学,所以有时我无法理解代码,这真的很有帮助。我最终在闭包之外创建了一个变量,将其设置在闭包中,然后将其返回。我认为它工作正常(如果我错了,请纠正我)但是现在当我在其他函数中调用 read 函数时,似乎代码执行不正常。我想我需要一个我现在正在阅读的完成处理程序,但是如果您有任何建议,我很想听听!
  • Firebase 是异步的,因此让 Firebase 闭包控制其余代码的节奏。 #1 事情是不要尝试从闭包返回数据 - 在闭包之外设置类级别的 var 很好,但请确保在闭包完成之前不要做任何该 var 的事情。正如您所提到的,您可以利用完成处理程序。但是,假设您正在填充 tableView 数据源;从 Firebase 读取数据,对其进行迭代以填充数组,然后仍在闭包内,在 for 循环之后,调用 tableView.reloadData。如果您遇到困难,请发布另一个问题!

标签: swift firebase google-cloud-firestore codable decodable


【解决方案1】:

我意识到 Result 对象的问题是 Xcode 将它作为我在不同文件中创建的结构来读取,但是一旦我更改了该结构的名称(它以前被命名为 Result),它就会识别 Result 对象作为正确的对象类型:枚举结果失败:错误

【讨论】:

    【解决方案2】:

    看起来您已经接近了 - 减去类型错误。据我所知,您的错误:

    Cannot invoke initializer for type 'Result' with an argument list of type '(@escaping () throws -> CombinedModel?)'

    参考这部分代码:

    let result = Result {
        try document.flatMap {
            try $0.data(as: CombinedModel.self)
        }
    }
    

    至少,这部分代码对我来说很有吸引力。您的 (document, error) 变量作为一个整体代表您的结果。您不需要Result 中间人。

    真正的重点应该是确定是否存在错误。如果没有,您应该阅读文档。

    一个可行的方法应该是这样的:

    func newReadData(word: String) -> CombinedModel? {
        let docRef = db.collection(K.FBConstants.dictionaryCollectionName).document(word)
    
        docRef.getDocument { (document, error) in
            guard let fbDoc = document else {
                // document is nil, parse the error object and handle it.
            }
    
            if let resultData = try fbDoc?.data(as: CombinedModel.self) {
                return resultData
            } else {
                return nil
            }
        }
    }
    

    让我知道这对你有什么好处!祝你好运。

    【讨论】:

    • 谢谢你,这肯定会奏效,我很感激你的回答。实际上,我刚刚意识到 Result 对象的问题是 Xcode 将它作为我创建的结构读取,但是一旦我更改了该结构的名称,它就会将 Result 对象识别为正确的对象: enum Result where Failure :错误
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-12-24
    • 2018-09-05
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多