简体   繁体   中英

DispatchGroup notify() called immediately - not waiting for Enter/Leave

I've been stuck with this problem for some time now, and I ran out of useful google results.

I've got two requests, the first one retrieves some links from a server and in the other request I download the images from the links. After all the images finished downloading, I return the result to a view controller.

Int the code requestBanners() is called from a UIViewController, entering the dispatch group. In theory, before leaving the dispatch group storeImage() should be called for every url that I got from the server, and on every call it should enter and leave the dispatch group, adding the image to an array. Once finished downloading all the images, it leaves the dispatch group, and fires the notify() to execute setUpCollection() on the UIViewController.

Using print() as guidance to see what's really happening, I get:

I'm downloading the urls

Now I'm in the UIViewController (this print() is called in the implementation of setUpCollection() )

I'm downloading an image

When it actually should be downloading the urls, then downloading the images and only then, returning to the UIViewController

I've used semaphores at first, but then I thought using a dispatch group would be a cleaner solution.

On both approaches, the empty bannersArr is returned before finishing downloading the images. Maybe that compact map is messing everything up.

Here's the code:

class BannersHelper {
    
    private var bannersArr: [UIImage] = []
    private let dispatchGroup = DispatchGroup()
    private var delegate: LoadBanners? = nil
    
    init(delegate: LoadBanners) {
        self.delegate = delegate
        
        dispatchGroup.notify(queue: .main) {
            self.delegate?.setUpCollection(errImg: self.bannersArr)
        }
    }
    
    func requestBanners() {
        print("I'm downloading the urls\n")
        self.dispatchGroup.enter()
        ServiceParametria.getBanners(handler: { response in
            guard let bannersResponse = response as? BannerModel else {
                return
            }
            
            let banners = bannersResponse.data as! [DataBannerModel]
            let _ = banners.compactMap({self.storeImage(model: $0)})
            self.dispatchGroup.leave()
        })
    }
    
    private func storeImage(model: DataBannerModel) {
        print("I'm downloading an image\n")
        self.dispatchGroup.enter()
        ServiceParametria.getImage(url: model.urlImagen!, handler: { result in
            let image = result as! UIImage
            self.bannersArr.append(image)
            self.dispatchGroup.leave()
        })
    }
}

Is there a better way to do this or am I just using the dispatch group wrong?

As @pkamb pointed out in the comments the problem was that I was trying to fire the dispatchGroup.notify() inside the init() method.

At that time of the execution, as I didn't call requestBanners() yet, the DispatchGroup counter was equal to zero and that led to a an early call to the delegate?.setUpCollection() with an empty array.

Moving the dispatchGroup.notify() block at the end of the requestBanners() method solved the problem :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM