i trying use grand central dispatch wait files finish download before continuing. question spin-off one: swift (ios), waiting images finish downloading before returning.
i trying find out how dispatch_group_wait (or similar) wait , not continue before downloads have finished. note if use nsthread.sleepfortimeinterval instead of calling downloadimage, waits fine.
what missing?
class imagedownloader { var updateresult = adupdateresult() private let filemanager = nsfilemanager.defaultmanager() private let imagedirectoryurl = nsurl(fileurlwithpath: settings.addirectory, isdirectory: true) private let group = dispatch_group_create() private let downloadqueue = dispatch_queue_create("com.acme.downloader", dispatch_queue_serial) func downloadimages(imagefilesonserver: [adfileinfo]) { dispatch_group_async(group, downloadqueue) { serverfile in imagefilesonserver { print("start downloading \(serverfile.filename)") //nsthread.sleepfortimeinterval(3) // using sleep instead of calling downloadimage makes dispatch_group_wait below work self.downloadimage(serverfile) } } dispatch_group_wait(group, dispatch_time_forever); // not wait downloads finish. why? print("all done!") // gets here early! } private func downloadimage(serverfile: adfileinfo) { let destinationpath = imagedirectoryurl.urlbyappendingpathcomponent(serverfile.filename) alamofire.download(.get, serverfile.imageurl) { temporaryurl, response in return destinationpath } .response { _, _, _, error in if let error = error { print("error downloading \(serverfile.filename): \(error)") } else { self.updateresult.filesdownloaded++ print("done downloading \(serverfile.filename)") } } } }
note: these downloads in response http post request , using http server (swifter) not support asynchronous operations, need wait full downloads complete before returning response (see original question referenced above more details).
when using dispatch_group_async
call methods are, themselves, asynchronous, group finish of asynchronous tasks have started, not wait them finish. instead, can manually call dispatch_group_enter
before make asynchronous call, , call dispatch_group_leave
when asynchronous call finish. dispatch_group_wait
behave expected.
to accomplish this, though, first change downloadimage
include completion handler parameter:
private func downloadimage(serverfile: adfileinfo, completionhandler: (nserror?)->()) { let destinationpath = imagedirectoryurl.urlbyappendingpathcomponent(serverfile.filename) alamofire.download(.get, serverfile.imageurl) { temporaryurl, response in return destinationpath } .response { _, _, _, error in if let error = error { print("error downloading \(serverfile.filename): \(error)") } else { print("done downloading \(serverfile.filename)") } completionhandler(error) } }
i've made completion handler passes error code. tweak see fit, illustrates idea.
but, having provided completion handler, now, when downloads, can create group, "enter" group before initiate each download, "leave" group when completion handler called asynchronously.
but dispatch_group_wait
can deadlock if you're not careful, can block ui if done main thread, etc. better, can use dispatch_group_notify
achieve desired behavior.
func downloadimages(imagefilesonserver: [adfileinfo], completionhandler: (int) -> ()) { let group = dispatch_group_create() var downloaded = 0 serverfile in imagefilesonserver { dispatch_group_enter(group) print("start downloading \(serverfile.filename)") self.downloadimage(serverfile) { error in if error == nil { downloaded += 1 } dispatch_group_leave(group) } } dispatch_group_notify(group, dispatch_get_main_queue()) { completionhandler(downloaded) } }
and you'd call so:
downloadimages(arrayofadfileinfo) { downloaded in // initiate whatever want when downloads done print("all done! \(downloaded) downloaded successfully.") } // don't contingent upon downloading of images here
Comments
Post a Comment