【问题标题】:Completion block for nested requests嵌套请求的完成块
【发布时间】:2018-09-12 14:35:54
【问题描述】:

我正在尝试为嵌套请求构建带有完成块的方法。问题是父请求的完成块会提前捕获(这意味着子请求实际上尚未完成)。到目前为止,除了我在下面的示例中所做的之外,我还没有找到一种方法让子请求与父请求进行通信(即计算子请求已完成的数量并将其与预期数量进行比较请求)。

以下示例针对 Firestore 数据库。想象一个用户有多个纸牌游戏(套牌),每张牌都有多张牌。对于如何为此类情况构建更好的完成块的任何帮助,我表示感谢:

func fetchCardsCount(uid: String, completion: @escaping (Int) -> ()) {
    let db = Firestore.firestore()


    var decksCount = Int()
    var cardsCount = Int()

    db.collection("users").document(uid).collection("decks").getDocuments { (deckSnapshot, err) in
        if let err = err {
            print("Error fetching decks for user: ", err)
        } else {
            guard let deckSnapshot = deckSnapshot else { return }

            deckSnapshot.documents.forEach({ (deck) in
                let dictionary = deck.data() as [String: Any]
                let deck = FSDeck(dictionary: dictionary)
                db.collection("users").document(uid).collection("decks").document(deck.deckId).collection("cards").getDocuments(completion: { (cardSnapshot, err) in
                    if let err = err {
                        print("Error fetching cards for deck: ", err)
                    } else {
                        guard let cardSnapshot = cardSnapshot else { return }
                        decksCount += 1
                        cardsCount += cardSnapshot.count

                        if decksCount == deckSnapshot.count {
                            completion(cardsCount)
                        }
                    }
                })
            })
        }
    }
}

【问题讨论】:

  • DispatchGroup 可能是您正在寻找的。​​span>
  • @meggar 介意详细说明吗?对我来说,将任务放在另一个线程上如何有助于捕获完成对我来说不是很明显?
  • 我在想completion(cardsCount) 会移到forEach 循环之外,因为如果我没看错的话,它看起来就是它所属的地方。然后,如果对“卡片”的请求在其他线程上,则可以使用 dispatchGroup 等待它们完成。
  • @meggar gotcha - 我从来没有在这种情况下使用调度组。你会怎么写?
  • dispatchGroup 将在forEach 循环之前创建,然后在forEach 循环中添加dispatchGroup.enter() 作为第一行,并在完成中添加dispatchGroup.leave() 作为最后一行。然后在forEach 循环之后添加dispatchGroup.notify(...)

标签: ios swift firebase request completion


【解决方案1】:

这是使用 DispatchGroup 的解决方案,在 cmets 中通过 @meggar 的帮助找到:

func fetchCardsCount(uid: String, completion: @escaping (Int) -> ()) {
    let db = Firestore.firestore()

    var cardsCount = Int()
    let group = DispatchGroup()

    group.enter()
    db.collection("users").document(uid).collection("decks").getDocuments { (deckSnapshot, err) in
        if let err = err {
            print("Error fetching decks for user: ", err)
        } else {
            guard let deckSnapshot = deckSnapshot else { return }

            deckSnapshot.documents.forEach({ (deck) in
                let dictionary = deck.data() as [String: Any]
                let deck = FSDeck(dictionary: dictionary)

                group.enter()
                db.collection("users").document(uid).collection("decks").document(deck.deckId).collection("cards").getDocuments(completion: { (cardSnapshot, err) in
                    if let err = err {
                        print("Error fetching cards for deck: ", err)
                    } else {
                        guard let cardSnapshot = cardSnapshot else { return }
                        cardsCount += cardSnapshot.count
                    }
                    group.leave()
                })
            })
        }
        group.leave()
    }

    group.notify(queue: .main) {
        completion(cardsCount)
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多