我正在制作一张表格,将3-4张照片上传到firebase存储空间。 上传完所有照片后,我想执行一个segue
self.performSegue(withIdentifier: "createClubToClubDetail", sender: self)
如何在调用performSegue之前检查是否所有照片都上传到firebase。
在for
循环之后放置上面的代码行不起作用,因为上传照片在不同的线程中运行(?)
let storageRef = Storage.storage().reference(forURL: "xxxxx.appspot.com").child("club_photo").child(clubRef.key)
for p in selectedImage {
let imageData = UIImageJPEGRepresentation(p.value, 0.005)
let storageImgRef = storageRef.child(p.key + ".jpg")
storageImgRef.putData(imageData!, metadata: nil) { (metadata, error) in
if error != nil {
print(error!)
return
}
let downloadURL = metadata?.downloadURL()?.absoluteString
var photoRef: DatabaseReference!
if p.key == "main" {
photoRef = ref.child("photo").child(clubRef.key).child("main")
}
if p.key == "sub1" {
photoRef = ref.child("photo").child(clubRef.key).child("sub1")
}
if p.key == "sub2" {
photoRef = ref.child("photo").child(clubRef.key).child("sub2")
}
if p.key == "sub3" {
photoRef = ref.child("photo").child(clubRef.key).child("sub3")
}
photoRef.setValue(downloadURL)
print("Upload photo: \(p.key)")
}
}
self.performSegue(withIdentifier: "createClubToClubDetail", sender: self)
答案 0 :(得分:2)
如前所述,标准DispatchGroup
API能够为您的问题提供一个很好的解决方案。由于您很可能在应用程序的其他地方也需要此功能,因此我尝试将基于DispatchGroup
的解决方案封装在一个不错的帮助程序类中:
//
// UploadTracker.swift
//
import Foundation
import FirebaseDatabase
class UploadTracker {
private let group = DispatchGroup()
fileprivate func trackSetValue(_ value: Any?, ref: DatabaseReference) {
group.enter()
ref.setValue(value) { (error, _) in
assert(error != nil, "\(error)")
self.group.leave()
}
}
func uploadDidFinish(block: @escaping () -> Void) {
group.notify(queue: .main) { block() }
}
}
extension DatabaseReference {
func setValue(_ value: Any?, trackedBy tracker: UploadTracker) {
tracker.trackSetValue(value, ref: self)
}
}
在原始代码中,使用情况为:
let uploadTracker = UploadTracker()
for p in selectedImage {
...
photoRef.setValue(downloadURL, trackedBy: uploadTracker)
}
uploadTracker.uploadDidFinish {
self.performSegue(withIdentifier: "createClubToClubDetail", sender: self)
}
答案 1 :(得分:0)
我已尝试使用以下代码上传多张图片并在上次上传完成时执行segue,虽然这是一个临时修复,但它确实有效。
当用户想要将多个图像保存到firebase存储时,会调用 saveToServerButtonPressed
方法。 selectedImages
是UiImage
类型的数组,包含用户要上传的所有图像。 var counter
仅用于捕获上一张图像的成功上传,以便用户可以导航到其他屏幕/只有在完成所有上传后才能执行的任何其他任务。
@IBAction func saveToServerButtonPressed(_ sender: Any) {
var counter = 0
for image in selectedImages {
uploadImage(image, progressBlock: { (progressValue) in
self.progressStatus.text = "\(progressValue)%"
}) { (downloadUrl, error) in
if error == nil {
if let downloadUrl1 = downloadUrl
{
counter += 1
self.imagesUrls.append(downloadUrl1)
if counter == self.selectedImages.count {
self.performSegue(withIdentifier: "showDownloadedSegue", sender: self)
}
}
} else {
print("Error Occured \(String(describing: error))")
}
}
}
}
实际在firebase上传图像的方法
func uploadImage(_ image: UIImage, progressBlock: @escaping (_ percentage: Double) -> Void, completionBlock: @escaping (_ url: URL?, _ errorMessage: String?) -> Void) {
let storage = FIRStorage.storage()
let storageReference = storage.reference()
let imageName = "\(Date().timeIntervalSince1970).jpg"
let imagesReference = storageReference.child(imageName)
if let imageData = UIImageJPEGRepresentation(image, 0.8) {
let metadata = FIRStorageMetadata()
metadata.contentType = "image/jpeg"
let uploadTask = imagesReference.put(imageData, metadata: metadata, completion: { (metadata, error) in
if let metadata = metadata {
completionBlock(metadata.downloadURL(), nil)
} else {
completionBlock(nil, error?.localizedDescription)
}
})
uploadTask.observe(.progress, handler: { (snapshot) in
guard let progress = snapshot.progress else {
return
}
let percentage = (Double(progress.completedUnitCount) / Double(progress.totalUnitCount)) * 100
progressBlock(percentage)
})
} else {
completionBlock(nil, "Image couldn't be converted to Data.")
}
}
}
注意:此代码在Swift 4上运行良好