I have a method to retrieve data. This data can but doesn't have to contain an image. The method below is retrieving the data in order which is crucial for the app:
static func getWishes(dataSourceArray: [Wishlist], completion: @escaping (_ success: Bool, _ dataArray: [Wishlist]) -> Void){
var dataSourceArrayWithWishes = dataSourceArray
let db = Firestore.firestore()
let userID = Auth.auth().currentUser!.uid
var j = 0
let dispatchSemaphore = DispatchSemaphore(value: 0)
let dispatchSemaphoreOuter = DispatchSemaphore(value: 0)
let dispatchQueue1 = DispatchQueue(label: "taskQueue")
var listCounter = 0
dispatchQueue1.async {
for list in dataSourceArray {
listCounter += 1
db.collection("users").document(userID).collection("wishlists").document(list.name).collection("wünsche").order(by: "wishCounter").getDocuments() { ( querySnapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
// dispatch group to make sure completion only fires when for loop is finished
// append every Wish to array at wishIDX
var i = 0
let dispatchQueue = DispatchQueue(label: "taskQueue1")
if (querySnapshot?.documents.count)! > 0 {
dispatchQueue.async {
for document in querySnapshot!.documents {
let documentData = document.data()
let imageUrlString = document["imageUrl"] as? String ?? ""
if let imageUrl = URL(string: imageUrlString) {
KingfisherManager.shared.retrieveImage(with: imageUrl, options: nil, progressBlock: nil, completionHandler: { result in
var image = UIImage()
switch result {
case .success(let abc):
image = abc.image
case .failure(let error):
print(error)
break
}
dataSourceArrayWithWishes[wishIDX].wishes.append(Wish(image: image))
i = i + 1
if i == querySnapshot?.documents.count {
j = j + 1
dispatchSemaphoreOuter.signal()
dispatchSemaphore.signal()
if j == dataSourceArray.count {
print("completion1")
completion(true, dataSourceArrayWithWishes)
}
} else {
dispatchSemaphore.signal()
}
})
} else {
dataSourceArrayWithWishes[wishIDX].wishes.append(Wish(image: image))
i = i + 1
if i == querySnapshot?.documents.count {
j = j + 1
dispatchSemaphoreOuter.signal()
dispatchSemaphore.signal()
if j == dataSourceArray.count {
print("completion3")
completion(true, dataSourceArrayWithWishes)
}
} else {
dispatchSemaphore.signal()
}
}
dispatchSemaphore.wait()
}
}
} else {
j = j + 1
dispatchSemaphoreOuter.signal()
}
}
}
// without this code the function will not fire a completion if only a single empty list is in dataSourceArray
// if listCounter == dataSourceArray.count {
// print("completion")
// completion(true, dataSourceArrayWithWishes)
// }
// continue
}
}
}
This method works fine if if (querySnapshot?.documents.count)! > 0
is true
but if a dataSourceArray
only contains an empty list
it fails because it never fires the completion
. I tried fixing that with a listCounter
and with the code at the bottom. This sort of works but is not clean because that always fires 2 completions
which looks weird in the app. Anyone have an idea on how I could fix the issue if there is only an empty list
in dataSourceArray
?
I am really stuck here so I am happy for every help!