#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 оказал вам обширную помощь, затем вы удалили этот вопрос, и теперь вы используете его код без кредита, и вы спрашиваете об этом как о новом вопросе?