Search code examples
iosswiftspinnergrand-central-dispatch

Where to Put DispatchQueue Swift


I am a new developer. I'm using Swift 4.2 and Xcode 10.2.

I'm trying to show a spinner while a photo is being saved. I am simulating a slow connection on my iPhone in Developer Mode to test it. Using the code below the spinner does not show up. The view goes right to the end where the button shows and says the upload is complete (when it isn't). I tried putting it all into a DispatchQueue.global(qos: .userinitiated).async and then showing the button back on the main queue. I also tried putting the showSpinner on a DispatchQueue.main and then savePhoto on a .global(qos: .utility). But I cleary don't understand the GCD processes.

Here's my code:

func savePhoto(image:UIImage) {

        // Add a spinner (from the Extensions)
        self.showSpinner(onView: self.view)

        PhotoService.savePhoto(image: image) { (pct) in

            // Can show the loading bar here.

        }

       // Stop the spinner
       self.removeSpinner()

       // Show the button.
       self.goToPhotosButtonLabel.alpha = 1
       self.doneLabel.alpha = 1
}

What types of DispatchQueues should I use and where should I put them?

Here is the savePhoto code:

static func savePhoto(image:UIImage, progressUpdate: @escaping (Double) -> Void) {

    // Get data representation of the image
    let photoData = image.jpegData(compressionQuality:0.1)

    guard photoData != nil else {
        print("Couldn't turn the image into data")
        return
    }

    // Get a storage reference
    let userid = LocalStorageService.loadCurrentUser()?.userId
    let filename = UUID().uuidString
    let ref = Storage.storage().reference().child("images/\(String(describing: userid))/\(filename).jpg")

    // Upload the photo
    let uploadTask = ref.putData(photoData!, metadata: nil) { (metadata, error) in

        if error != nil {

            // An error during upload occurred
            print("There was an error during upload")
        }
        else {
            // Upload was successful, now create a database entry
            self.createPhotoDatabaseEntry(ref: ref, filename: filename)

        }
    }

    uploadTask.observe(.progress) { (snapshot) in

        let percentage:Double = Double(snapshot.progress!.completedUnitCount /
        snapshot.progress!.totalUnitCount) * 100.00

        progressUpdate(percentage)
    } 

}

Solution

  • Since the code that saves the photo is asynchronous , so your current code removes the spinner directly after it's added before the upload is complete

    func savePhoto(image:UIImage) {
    
        // Add a spinner (from the Extensions)
        self.showSpinner(onView: self.view)
    
        PhotoService.savePhoto(image: image) { (pct) in
    
           //  remove spinner when progress is 100.0  = upload complete .
           if pct == 100.0 {
               // Stop the spinner
               self.removeSpinner() 
                // Show the button.
               self.goToPhotosButtonLabel.alpha = 1
               self.doneLabel.alpha = 1
    
            }
        } 
    } 
    

    Here you don't have to use GCD as firebase upload runs in another background thread so it won't block the main thread