Как я могу исправить ошибку при оставлении диспетчерской группы в swift

#ios #swift #firebase #realm

#iOS #swift #firebase #область

Вопрос:

Я хочу загрузить все данные из firebase, а затем отобразить данные в табличном представлении. Но теперь я не могу отобразить все данные в табличном представлении. Это связано с тем, что вызов метода finishLoading (realm) выполняется быстрее, чем цикл for, который получает все данные. Как я могу показать все данные, когда цикл for завершен в swift. Я должен использовать закрытие, однако вторая часть цикла позже, чем эта «self.finishLoading (realm: realm)»

Однако я должен попытаться добавить DispatchGroup(), leave() при возникновении ошибки EXC_BAD_INSTRUCTION . Могу ли я поместить leave() в закрытие? Как я могу это исправить?

   func loopAllProduct(userId: String, finishLoadWhenErr:Bool, storedClosure: @escaping (DocumentSnapshot) -> Void){
        let storage = Storage.storage()
        let db = Firestore.firestore()
        let userDocRef = db.collection("Users").document(userId).collection("Product")
        userDocRef.getDocuments{(document, error) in
            if let err = error {
                print("Error getting documents: (err)")
            } else {
                for document in document!.documents {
                    storedClosure(document)
                }
            }
        }

    }
    func downloadData() {
        let startTime = Date()
        while updating {
            let diffTime = Date(timeIntervalSinceReferenceDate: startTime.timeIntervalSinceReferenceDate)
            if (diffTime.timeIntervalSinceNow < -5){
                self.stopAnimating()
                self.refreshControl?.endRefreshing()
                print("Update Timeout")
                return
            }
        }
        updating = true
        let storage = Storage.storage()
        let db = Firestore.firestore()
        let productLoading = NSMutableArray()
        let realm = try! Realm()
        print("all posts")
        let group = DispatchGroup()
        let addPosts: (DocumentSnapshot)->Void = {(document) in
                try! realm.write {
                    if let resuls = self.realmResults {
                        realm.delete(resuls);
                    }
                }

                let product = Product()
                product.id = document.documentID
                product.userID = document.data()?["UserID"] as? String
                product.userName = document.data()?["UserName"] as? String
                product.descrition = document.data()?["Descrition"] as? String
                product.postTime = document.data()?["PostTime"] as? Date
                product.price = document.data()?["Price"] as? Double ?? 0.0
                product.stat = (document.data()?["stat"] as? Int)!
                product.productName = document.data()?["ProductName"] as? String
                let productId = document.documentID
                productLoading.add(productId)
                try! realm.write {
                    realm.add(product)
                }
             group.leave()
        }
        let userDocRef = db.collection("Users")
        userDocRef.getDocuments{(document, error) in
        for document in document!.documents {
                group.enter()
                self.loopAllProduct(userId:document.documentID , finishLoadWhenErr: true, storedClosure: addPosts)
            }
        }
        group.notify(queue: DispatchQueue.main) {
            self.finishLoading(realm: realm)
         }
    }
  

Комментарии:

1. Вам нужно войти в enter группу перед вызовом getDocuments , иначе notify она сработает немедленно. Предполагая, что updating изначально false ваш while цикл будет пропущен. Если updating значение равно false, оно заблокирует основной поток на 5 секунд (что плохо)

2. Вопрос немного расплывчатый, и вы можете столкнуться с асинхронной проблемой с Realm и Firebase. Я вижу, что это self.loopAllProduct(use вызывается в замкнутом цикле и непосредственно после этого у вас есть group.notify(queue: , который будет вызван до того, как Firebase сможет вернуть данные. Вы должны настроить свой код так, чтобы он работал только с данными, возвращаемыми из Firebase при закрытии , и не ожидать, что код, следующий за закрытием, будет выполняться первым. Кроме того, вы внедрили DispatchQueue, которые часто не нужны, поскольку вызовы закрытия Firebase (кроме пользовательского интерфейса) выполняются в фоновом режиме.

3. Что случилось с вашей более ранней версией этого вопроса? Вы задали вопрос, @vadian оказал вам обширную помощь, затем вы удалили этот вопрос, и теперь вы используете его код без кредита, и вы спрашиваете об этом как о новом вопросе?