objective c - Parse PFFile download order iOS -
i'm storing 5 pffiles in array , using getdatainbackgroundwithblock
download files parse.
the problem order @ appear in table view cells different every time, presumably because files download @ different speeds due different file sizes.
for (pffile *imagefile in self.imagefiles) { [imagefile getdatainbackgroundwithblock:^(nsdata *imagedata, nserror *error) { if (!error) { uiimage *avatar = [uiimage imagewithdata:imagedata]; [self.avatars addobject:avatar]; cell.userimageview.image = self.avatars[indexpath.row]; } }]; }
the self.imagefiles
array in correct order. how ensure images downloaded added self.avatars
array in same order self.imagefiles
?
the question has 2 parts: (1) explicitly, how maintain order of results of asynchronous operations, (2) implied use of cell
, how handle asynch requests in support of tableview.
the answer first question simpler: keep result of request associated parameter request.
// change avatars hold dictionaries associating pffiles images @property(nonatomic,strong) nsmutablearray *avatars; // initialize (pffile *imagefile in self.imagefiles) { [avatars addobject:[@{@"pffile":imagefile} mutablecopy]]; } // lets factor avatar fetch own method - (void)avatarforindexpath:(nsindexpath *)indexpath completion:^(uiimage *, nserror *)completion { // if fetched already, return via completion block uiimage *existingimage = self.avatars[indexpath.row][@"image"]; if (existingimage) return completion(existingimage, nil); pffile *pffile = self.avatars[indexpath.row][@"pffile"]; [pffile getdatainbackgroundwithblock:^(nsdata *imagedata, nserror *error) { if (!error) { uiimage *avatar = [uiimage imagewithdata:imagedata]; self.avatars[indexpath.row][@"image"] = avatar; completion(avatar, nil); } else { completion(nil, error); } }]; }
okay part (1). part 2, cellforrowatindexpath
code must recognize cells reused. time asynch image fetch happens, cell you're working on might have scrolled away. fix not referring cell in completion block (only indexpath
).
// somewhere in cellforrowatindexpath // we're ready setup cell's image view uiimage *existingimage = self.avatars[indexpath.row][@"image"]; if (existingimage) { cell.userimageview.image = existingimage; } else { cell.userimageview.image = // can put placeholder image here while fetch [self avatarforindexpath:indexpath completion:^(uiimage *image, nserror *error) { // here's trick missed, don't refer cell, instead: if (!error) { [tableview reloadrowsatindexpaths:@[indexpath]]; } }]; }
reloading row in completion block cause cellforrowatindexpath
called again, except on subsequent call, we'll have existing image , cell configured immediately.
Comments
Post a Comment