-3

I have a following code structure, how can I run this code on background thread and execute all the methods serially in FIFO.

How to wait for function to executes all its statements and then move to next function?


func downloadImagesAndProcess(){
// i need these methods to execute one by one i.e when saveimages completes fully only then call resizeimages
saveImages()
resizeImages()
shareImgs()

}

func saveImages(){

// long async tasks

for (index, image) in (self.images.enumerated())! {
              
     KingfisherManager.shared.retrieveImage(with: URL(string:image.imageFile)!) { result in
                    
                    switch result {
                    case .success(let value):
                    self.saveImageDocumentDirectory(image: value.image, imageName: imgNameStr)

                    case .failure(let error):
                        print(error) // The error happens
                    }
                  
                }
              
            }

}

func resizeImages(){

// long running tasks

}

func shareimgs(){

//share
}

I need these methods to execute one by one i.e. when saveImages completes fully only then call resizeImages

How to wait for function to executes all its statements and then move to next function?

Neil Turner
  • 2,712
  • 2
  • 18
  • 37
imgroot
  • 131
  • 3
  • 11

2 Answers2

2

You can use this framework for Swift coroutines - https://github.com/belozierov/SwiftCoroutine

When you call await it doesn’t block the thread but only suspends coroutine, so you can use it in the main thread as well.

func saveImages() {
    DispatchQueue.main.startCoroutine {
        let manager = KingfisherManager.shared

        for (index, image) in (self.images.enumerated())! {
            let url = URL(string: image.imageFile)!

            let result = try Coroutine.await {
                manager.retrieveImage(with: url, completionHandler: $0)
            }

            switch result {
            case .success(let value):
                self.saveImageDocumentDirectory(image: value.image, imageName: imgNameStr)
            case .failure(let error):
                print(error)
            }
        }

        self.resizeImages()
    }
}
Alex Belozierov
  • 131
  • 1
  • 4
1

The easiest thing to do is call the next method inside the completion of the previous one

func saveImages(){

    let group = DispatchGroup()
    for (index, image) in (self.images.enumerated())! {
        group.enter()
        KingfisherManager.shared.retrieveImage(with: URL(string:image.imageFile)!) { result in
            switch result {
            case .success(let value):
                self.saveImageDocumentDirectory(image: value.image, imageName: imgNameStr)
            case .failure(let error):
                print(error) // The error happens
            }
            group.leave()
        }
    }
    group.notify(queue: .main) {
        // do your stuff, check if every image has been downloaded
        self.resizeImages() // this will be called after the completion of the current task
    }
}

Then in the resizeImages I guess there's another completion handler, inside that you'll call shareImgs

Rico Crescenzio
  • 3,952
  • 1
  • 14
  • 28
  • I used a `DispatchGroup` to load multiple images, because their downloading start at the same time, but then you have to wait until every process is done. When all tasks are done, the notifiy gets called. – Rico Crescenzio Apr 03 '19 at 13:09
  • i used DispatchGroup but when using dispatch group with background queue blocks it doesnt waits – imgroot Apr 03 '19 at 13:12
  • I can't see any background queue implementation in your code, I cannot help you more than this – Rico Crescenzio Apr 03 '19 at 13:14
  • just i want to know how to wait and serially execute methods using background queue ? – imgroot Apr 03 '19 at 13:17
  • Why you put that loop inside a background queue? `KingfisherManager.shared.retrieveImage` is already running in another queue (otherwise there wouldn't be any completion handler) – Rico Crescenzio Apr 03 '19 at 13:17