multithreading - iOS: Keeping User Interface responsive while images are being loaded in a separate thread -
some context: have uicollectionview
display around thousand tiny images, though around 100 of them visible @ same time.
i need load images disk in separate thread, ui not blocked , user can interact app while images still appearing.
to so, i've implemented rob mayoff's answer proper way deal cell reuse background threads? in swift follows, potocell
subclass of uicollectionviewcell
:
var myqueue = dispatch_queue_create("com.dignityvalley.autoescuela3.photoqueue", dispatch_queue_serial) var indexpathsneedingimages = nsmutableset() func collectionview(collectionview: uicollectionview, cellforitematindexpath indexpath: nsindexpath) -> uicollectionviewcell { let cell = collectionview.dequeuereusablecellwithreuseidentifier(reuseidentifier, forindexpath: indexpath) as! photocell cell.imageview.image = nil indexpathsneedingimages.addobject(indexpath) dispatch_async(myqueue) { self.bg_loadoneimage() } return cell } func bg_loadoneimage() { var indexpath: nsindexpath? dispatch_sync(dispatch_get_main_queue()) { indexpath = self.indexpathsneedingimages.anyobject() as? nsindexpath if let indexpath = indexpath { self.indexpathsneedingimages.removeobject(indexpath) } } if let indexpath = indexpath { bg_loadimageforrowatindexpath(indexpath) } } func bg_loadimageforrowatindexpath(indexpath: nsindexpath) { if let cell = self.cellforitematindexpath(indexpath) as? photocell { if let image = self.photoforindexpath(indexpath) { dispatch_async(dispatch_get_main_queue()) { cell.imageview.image = image self.indexpathsneedingimages.removeobject(indexpath) } } } } func collectionview(collectionview: uicollectionview, didenddisplayingcell cell: uicollectionviewcell, foritematindexpath indexpath: nsindexpath) { indexpathsneedingimages.removeobject(indexpath) }
however, i'm not getting acceptable results: when scroll, ui freezes fraction of second while images being loaded in background. scrolling not smooth enough. moreover, while first 100 images being loaded, not able scroll @ until last image has been displayed. ui still being blocked after implementation of multithreading.
surprisingly, can achieve desired smoothness modifying queue to:
var myqueue = dispatch_get_global_queue(qos_class_background, 0)
note previosly using custom serial queue.
after change, ui responsive, have serious problem: app crashes occaionally, , think has fact several threads may accessing , modifying indexpathsneedingimages
@ same time.
trying use locks/syncronization makes images end wrong cells times. so, achieve smoothness gives me global background queue using cutom serial queue. can't figure out why ui freezing when use custom serial queue , why not when use global one.
some thoughts: maybe setting cell.imageview.image = image
around 100 cells takes time though image
has been allocated. problem may here, since commenting line makes scroll way smoother. don't understand why scrolling smooth when leave line uncommented , use global background-priority queue (until app crashes throwing message telling ... mutated while being enumerated
).
any ideas on how tackle this?
in function should dispatch_async main queue. reason should switch queues when getting data off network or doing task takes time , blocks ui. when asyncing main queue, ui related things should done.
func bg_loadoneimage() { var indexpath: nsindexpath? dispatch_sync(dispatch_get_main_queue()) { indexpath = self.indexpathsneedingimages.anyobject() as? nsindexpath if let indexpath = indexpath { self.indexpathsneedingimages.removeobject(indexpath) } } if let indexpath = indexpath { bg_loadimageforrowatindexpath(indexpath) } }
also if let indexpath = indexpath confusing
Comments
Post a Comment