ios - NSURLSession in For Loop to Download Image Data then add to NSMutableArray -
my application has uitableview cell contains uicollectionview subview (not reused). collectionview's cells have single uiimageview hold picture. trying download of images @ once, store them in array, , display contents of array in collectionview cell once images downloaded. in objc have done many times using nsurlconnection
trying use swift , nsurlconnection
achieve i'm running believe may either concurrency or semantics issues. maybe 1 of guys point me in right direction because feel i'm spending time on this.
in uitableview's cell subclass contains collectionview calling
func downloadphotoswithurls(urls: [string]) { var imagesmutablearray = nsmutablearray() url in urls { nsurlsession.sharedsession().datataskwithurl(nsurl(string: url)!, completionhandler: { (data, repsonse, err) -> void in if let imgdata = data { if let image = uiimage(data: imgdata) { imagesmutablearray.addobject(image) } else { // put in "photo unavailable" pic } } else { // put in "photo unavailable" pic } }).resume() } // update (but async op not done) if let downloadedimages: [uiimage] = imagesmutablearray nsarray as? [uiimage] { self.images = downloadedimages dispatch_async(dispatch_get_main_queue(), { () -> void in self.collectionview.reloaddata() }) } }
problem time call collectionview reloaded, images have not been fetched. asynchronous operations in loop blame. how call // update
code after images downloaded?
if want wait series of asynchronous tasks finish, create dispatch_group_t
, enter group before starting each request, leave group in completion block, , can rely on dispatch_group_notify
called when each "enter" matched "leave"
func downloadphotoswithurls(urls: [string]) { var images = [uiimage]() let group = dispatch_group_create() url in urls { dispatch_group_enter(group) nsurlsession.sharedsession().datataskwithurl(nsurl(string: url)!, completionhandler: { data, response, error in if let imgdata = data { if let image = uiimage(data: imgdata) { dispatch_sync(dispatch_get_main_queue()) { images.append(image) } } else { // put in "photo unavailable" pic } } else { // put in "photo unavailable" pic } dispatch_group_leave(group) }).resume() } // update dispatch_group_notify(group, dispatch_get_main_queue()) { self.images = images self.collectionview.reloaddata() } }
note, should synchronize updates of array of images (mutable arrays not thread safe).
--
having answered question, must confess advise 2 further, yet significant changes:
you shouldn't hold images in array (because if there many, can run out of memory). jpeg or png files might not large, when images uncompressed in ram, can take lot of memory , can memory warnings.
you might consider downloading images persistent storage, not memory. if want hold images in memory, use
nscache
performance reasons (but purge upon memory warning).if don't have many images, or they're small may not critical. if you're looking scalable solution, don't require app hold of images in array.
you might not want wait of images before reloading collection view. people advise lazy loading. if have 1000 images , 20 visible @ time, why wait 1000 images? focus on loading images visible cells. also, might want see images pop collection view they're downloaded (so rather waiting first 20 visible images downloaded, show them come in).
you accomplish having
cellforitematindexpath
initiate image download asynchronously , update cell when it's done.
Comments
Post a Comment