首页 > 解决方案 > 未正确等待来自 Firebase 的 Swift 查询

问题描述

我正在尝试从 Firebase 查询文档,但我无法正确等待函数的响应。我已经尝试过 Future,但似乎我无法从查询正文中返回承诺。您能帮我吗,如何正确查询然后使用 Swift (Combine) 和 Firebase 订阅它?

我需要知道查询的结果(错误/空/成功),如果成功,则使用查询的值。这可能吗?

查询:

func getProductByCode(code: String) -> Future<[Product], QueryError> {
        return Future { promise in
            self.db.collection("products")
            .whereField("code", isEqualTo: code)
            .getDocuments { (querySnapshot, error) in
                if let error = error {
                    print("Error on loading products: \(error.localizedDescription)")
                    return promise(.failure(.error))
                }
                
                if let querySnapshot = querySnapshot {
                    if querySnapshot.isEmpty {
                        print("Empty products list")
                        return promise(.failure(.empty))
                    } else {
                        self.products = querySnapshot.documents.compactMap { document in
                            try? document.data(as: Product.self)
                        }
                        print("List of products: \(self.products)")
                        return promise(.success(self.products))
                    }
                }
            }
        }
    }

enum QueryError: Error {
        case empty
        case error
    }

方法调用,订阅:

productRepository.getProductByCode(code: qrText)
    .sink(receiveCompletion: { completion in
            switch completion {
            case .failure(.error):
                print("ERROR on retrieving products")
            case .failure(.empty):
                print("EMPTY products")
            default:
                print("ALRIGHT")
            }
        }, receiveValue: { value in
            print("Returned value: \(value)")
            // Here I should get the result of the query and then use it.
        })

//After the method call I would like to use the result value.
//But I cannot correctly await it.
//It would be called before the async function returns the value.

我对任何形式的改变持开放态度,我尝试过 Future,因为它可以返回承诺,我们可以订阅它。如果有更好的解决这种情况的方法,请帮忙。

标签: swiftfirebasefuturecombine

解决方案


如果我理解正确。问题的症结在于网络请求的异步性。

productRepository.getProductByCode(code: qrText)
    .sink(receiveCompletion: { completion in
            switch completion {
            case .failure(.error):
                print("ERROR on retrieving products")
            case .failure(.empty):
                print("EMPTY products")
            default:
                print("ALRIGHT")
            }
        }, receiveValue: { value in
            print("Returned value: \(value)")
            // Here I should get the result of the query and then use it.
        })

// You want to use the value here? For example:
self.label.text = value

您是否可以使用函数来完成您想要使用该值的目的,或者将使用该值的代码放在receiveValue块中?例如:

productRepository.getProductByCode(code: qrText)
    .sink(receiveCompletion: { completion in
            switch completion {
            case .failure(.error):
                print("ERROR on retrieving products")
            case .failure(.empty):
                print("EMPTY products")
            default:
                print("ALRIGHT")
            }
        }, receiveValue: { value in
            print("Returned value: \(value)")
            updateLabel(value: value) // <- Function won't be called until this block fires and we have the `value`
        })

func updateLabel(value: String) {
    self.label.text = value
}

推荐阅读