这个forEach循环有时会起作用,有时它会跳过。我不确定我在这里做错了什么。循环将跳过最后一项,永远不会退出。所以完成块根本不会被触发。
我正在使用firebase,Eureka表格和它的ImageRow扩展程序。
我会在此感谢一些帮助。
//MARK: - Get Form Values
var returnedValues: [String: Any] = [:]
fileprivate func getFormValues(values: [String: Any], completion: @escaping ([String:Any])->()) {
if let name = values["name"] as? String,
let description = values["description"] as? String,
let images = values["images"] as? [UIImage],
let category = values["category"] as? String,
let price = values["price"] as? Double,
let deliveryFee = values["deliveryFee"] as? Double,
let deliveryAreas = values["deliveryArea"] as? Set<String>,
let deliveryTime = values["deliveryTime"] as? String {
guard let uid = Auth.auth().currentUser?.uid else { return }
var imagesData = [[String: Any]]()
var counter = 0
images.forEach({ (image) in
let imageName = NSUUID().uuidString
let productImageStorageRef = Storage.storage().reference().child("product_images").child(uid).child("\(imageName).jpg")
var resizedImage = UIImage()
if image.size.width > 800 {
resizedImage = image.resizeWithWidth(width: 800)!
}
if let uploadData = UIImageJPEGRepresentation(resizedImage, 0.5) {
productImageStorageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
if error != nil {
print("Failed to upload image: \(error?.localizedDescription ?? "")")
return
}
//Successfully uploaded product Image
print("Successfully uploaded product Image")
if let productImageUrl = metadata?.downloadURL()?.absoluteString {
counter += 1
let imageData: [String: Any] = [imageName: productImageUrl]
imagesData.append(imageData)
if counter == images.count {
let deliveryAreasArr = Array(deliveryAreas)
self.returnedValues = ["name": name, "description": description, "images": imagesData , "category": category, "price": price, "deliveryFee": deliveryFee, "deliveryArea": deliveryAreasArr, "deliveryTime": deliveryTime, "creationDate": Date().timeIntervalSince1970, "userId": uid]
completion(self.returnedValues)
}
}
})
}
})
} else {
let alert = UIAlertController(title: "Missing Information", message: "All fields are required. Please fill all fields.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in
alert.dismiss(animated: true, completion: nil)
}))
UIActivityIndicatorView.stopActivityIndicator(indicator: self.activityIndicator, container: self.activityIndicatorContainer, loadingView: self.activityIndicatorLoadingView)
self.present(alert, animated: true, completion: nil)
}
}
答案 0 :(得分:0)
if
循环中有许多for
语句可能导致counter
没有递增。如果其中任何一个失败,那么你永远不会调用完成处理程序。
我知道您正在使用counter
试图了解所有异步任务何时完成,但调度组是更好的解决方案。
在所有路径中调用完成处理程序也很重要;例如,当初始guard
失败或在初始else
的{{1}}子句中时 - 您的完成处理程序应该接受if
参数,以便它知道存在问题
Error
其他一些观点:
//MARK: - Get Form Values
fileprivate func getFormValues(values: [String: Any], completion: @escaping ([String:Any]?)->()) {
var returnedValues: [String: Any] = [:]
if let name = values["name"] as? String,
let description = values["description"] as? String,
let images = values["images"] as? [UIImage],
let category = values["category"] as? String,
let price = values["price"] as? Double,
let deliveryFee = values["deliveryFee"] as? Double,
let deliveryAreas = values["deliveryArea"] as? Set<String>,
let deliveryTime = values["deliveryTime"] as? String {
guard let uid = Auth.auth().currentUser?.uid else {
completion(nil)
return
}
var imagesData = [[String: Any]]()
let dispatchGroup = DispatchGroup() // Create a Dispatch Group
images.forEach({ (image) in
let imageName = NSUUID().uuidString
let productImageStorageRef = Storage.storage().reference().child("product_images").child(uid).child("\(imageName).jpg")
var resizedImage = UIImage()
if image.size.width > 800 {
resizedImage = image.resizeWithWidth(width: 800)!
}
if let uploadData = UIImageJPEGRepresentation(resizedImage, 0.5) {
dispatchGroup.enter() // Enter the group
productImageStorageRef.putData(uploadData, metadata: nil, completion: { (metadata, error) in
guard error == nil else {
print("Failed to upload image: \(error?.localizedDescription ?? "")")
dispatchGroup.leave() // Leave the dispatch group if there was an error
return
}
//Successfully uploaded product Image
print("Successfully uploaded product Image")
if let productImageUrl = metadata?.downloadURL()?.absoluteString {
let imageData: [String: Any] = [imageName: productImageUrl]
imagesData.append(imageData)
}
dispatchGroup.leave() // Leave the dispatch group in normal circumstances
})
}
})
// Schedule a notify closure for execution when the dispatch group is empty
dispatchGroup.notify(queue: .main) {
let deliveryAreasArr = Array(deliveryAreas)
returnedValues = ["name": name, "description": description, "images": imagesData , "category": category, "price": price, "deliveryFee": deliveryFee, "deliveryArea": deliveryAreasArr, "deliveryTime": deliveryTime, "creationDate": Date().timeIntervalSince1970, "userId": uid]
completion(self.returnedValues)
}
} else {
completion(nil)
let alert = UIAlertController(title: "Missing Information", message: "All fields are required. Please fill all fields.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { (_) in
alert.dismiss(animated: true, completion: nil)
}))
UIActivityIndicatorView.stopActivityIndicator(indicator: self.activityIndicator, container: self.activityIndicatorContainer, loadingView: self.activityIndicatorLoadingView)
self.present(alert, animated: true, completion: nil)
}
}
作为输入将在函数开头摆脱那个巨大的struct
,因为你会知道值的类型,并使它们成为你知道的结构的非可选属性价值观存在。if let
返回给调用者以指示存在问题并让调用者处理它throw
需要成为一系列词典。数组中的每个字典只有一个条目,因此您可以使用imagesData
的字典(当您知道类型将是什么时,无需使用[String:String]
。