objective c - Best practice for asynch loads that may be same address -


i download images amazon's web services uitableview. use singleton cache recent images. wondering how best handle situation where, example, have 2 cells in view , both using same key (url same scenario if using nsurlsession). there's no need download image twice, checking cache not return result first download not complete when second 1 begins. current logic use additional nsdictionary singleton contain key each image downloading, not complete. check against after checking cache, , if key exists, add reference of uiimageview key's array - when download complete, array can utilized update uiimageviews referenced in array. isn't "clean" way in opinion - there better practice handling this? while question more conception, here's current code:

custom_image_view.m

-(void)set_image:(nsstring *)key desired_size:(cgsize)desired_size { singleton *caches = [singleton instance]; if (!key.length || [key isequaltostring:@"0"]) {     return; } if (![caches is_file_cached:key type:image_cache]) { //should check new dictionary here see if it's downloading? //if downloading, add self array , return //if not downloading, make new key     nsstring *bucket = @"bucket.mysite.com";      nsarray *paths = nssearchpathfordirectoriesindomains(nsdocumentdirectory, nsuserdomainmask, yes);     nsstring *documents_directory = [paths objectatindex:0];     nsstring *image_path =[documents_directory stringbyappendingpathcomponent:[nsstring stringwithformat:@"%@.jpg",@"cached"]];  //only relevant aws users     awsstaticcredentialsprovider *credentialsprovider = [awsstaticcredentialsprovider credentialswithaccesskey:@"accesskey" secretkey:@"secretkey"];     awsserviceconfiguration *configuration = [awsserviceconfiguration configurationwithregion:awsregionuseast1 credentialsprovider:credentialsprovider];     [awsservicemanager defaultservicemanager].defaultserviceconfiguration = configuration;      download_request = [awss3getobjectrequest new];     download_request.bucket = bucket;     download_request.key = key;     download_request.downloadingfileurl = [nsurl fileurlwithpath:image_path];     awss3 *transfermanager = [[awss3 alloc] initwithconfiguration:configuration];     nslog(@"manager: %@",transfermanager); //begin request     [[transfermanager getobject:download_request] continuewithblock:^id(bftask *task)      {          if (task.error != nil)          {              nslog(@"error");              if(task.error.code != awss3transfermanagererrorcancelled && task.error.code != awss3transfermanagererrorpaused)              {                  nslog(@"error code: %@",task.error);                  nslog(@"key: %@",key);              }          }          else          {              //successful download              self->download_request = nil;              dispatch_async(dispatch_get_main_queue(), ^                             {                                 nsdata *data = [nsdata datawithcontentsoffile:image_path];                                 uiimage *image = [uiimage imagewithdata:data];                                 if (image != nil)                                 {                                     self.image = [self crop_image:image to_size:desired_size];      //loop through new dictionary's array , assign image each well?                                     [caches add_file_to_cache:key withdata:data type:image_cache];                                 }                             });          }          return nil;      }]; } else {     dispatch_async(dispatch_get_main_queue(), ^                    {                        nsdata *data = [caches get_cached_data:key type:image_cache];                        uiimage *image = [uiimage imagewithdata:data];                        self.image = [self crop_image:image to_size:desired_size];                    }); } } 

boltsframework has made task bit easier you, still need sort of cache.

getobject: returns bftask. continuewithblock: handy method on bftask execute block after task has completed. able attribute multiple blocks executed same task's completion, saving lot of work. that's left pull whole thing simple cache image_path bftasks. here's code better explain.

somewhere:

static nsmutabledictionary * _imagepathtotask = [nsmutabledictionary new]; 

instead of:

[[transfermanager getobject:download_request] continuewithblock:^id(bftask *task) { 

do this:

bftask *task = [_imagepathtotask objectforkey:image_path]; if (task == nil) {     task = [transfermanager getobject:download_request];     [_imagepathtotask setobject:task forkey:image_path]; } [task continuewithblock:^id(bftask *task) { 

even if task completed, block called task. long dictionary around, image requests can sent off knowing won't download same image twice.

now last thing sketchy how we're storing dictionary. better approach might create category awss3 returns bftask file path. doing make implementation above same amount of code in uiimageview category. use associated object store image_path->task dictionary on awss3 instance. reckon might wrap 1 of reuse anyhow, perhaps omitted code keep example brief.

edit: suppose more directly answer question, have right idea. if @ bftask , callbacks nsmutablearray, doing described. big difference level in application in doing it.


Comments

Popular posts from this blog

javascript - Jquery show_hide, what to add in order to make the page scroll to the bottom of the hidden field once button is clicked -

javascript - Highcharts multi-color line -

javascript - Enter key does not work in search box -