ios - UITableView with complex cells is slow and laggy -
i've finished app , seems work main view.
it's uiviewcontroller
embedded uitableview
.
i'm using parse backend, , array of objects need in viewdidload
method.
each cell contains data i'm fetching in tableview:cellforrowatindexpath
, i'm afraid reason why table view laggy, don't know how fetch data need each object in array without having indexpath.row
number.
i've made each cell element "opaque" suggested in other answers.
this code, appreciated:
- (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath { static nsstring *cellidentifier = @"cellht"; cellht *cell = (cellht *)[tableview dequeuereusablecellwithidentifier:cellidentifier]; if (!cell) { cell = [[cellht alloc] initwithstyle:uitableviewcellstyledefault reuseidentifier:cellidentifier]; } // self.hh nsarray containing objects nsuserdefaults *prefs = [nsuserdefaults standarduserdefaults]; cell.lbltitle.text = [self.hh[indexpath.row] objectforkey:@"title"]; cell.lblvenuename.text = [self.hh[indexpath.row] objectforkey:@"venuename"]; cell.lbldistance.text = nslocalizedstring(@"distance you", nil); self.geo = [self.hh[indexpath.row] objectforkey:@"coordinates"]; // formatters initialized in viewdidload: method self.formatdata = [nsdateformatter dateformatfromtemplate:@"dd/mm" options:0 locale:[nslocale currentlocale]]; [self.formatterdata setdateformat:self.formatdata]; self.formatora = [nsdateformatter dateformatfromtemplate:@"j:mm" options:0 locale:[nslocale currentlocale]]; [self.formatterora setdateformat:self.formatora]; self.dal = nslocalizedstring(@"from", nil); self.ore = nslocalizedstring(@"at", nil); cllocation *vloc = [[cllocation alloc] initwithlatitude:self.geo.latitude longitude:self.geo.longitude]; cllocation *user = [[cllocation alloc] initwithlatitude:self.usergeo.latitude longitude:self.usergeo.longitude]; cllocationdistance distance = [user distancefromlocation:venueloc]; if ([[prefs objectforkey:@"unit"] isequaltostring:@"km"]) { cell.lbldist.text = [nsstring stringwithformat:@"%.1f km", distance /1000]; } else { cell.lbldist.text = [nsstring stringwithformat:@"%.1f miles", distance /1609]; } // compare object's starting date current date set images in cell nscomparisonresult startcompare = [[self.hh[indexpath.row] objectforkey:@"startdate"] compare: [nsdate date]]; if (startcompare == nsordereddescending) { cell.quad.image = [uiimage imagenamed:@"no_ht"]; cell.lblstarttime.textcolor = [uicolor redcolor]; } else { cell.quad.image = [uiimage imagenamed:@"yes_ht"]; cell.lblstarttime.textcolor = [uicolor colorwithred:104.0/255.0 green:166.0/255.0 blue:66.0/255.0 alpha:1.0]; } nsstring *datainizio = [nsstring stringwithformat:@"%@ %@ %@ %@", self.dal, [self.formatterdata stringfromdate:[self.hh[indexpath.row] objectforkey:@"startdate"]], self.ore, [self.formatterora stringfromdate:[self.hh[indexpath.row] objectforkey:@"enddate"]]]; cell.lblstarttime.text = datainizio; pfobject *cat = [self.hh[indexpath.row] objectforkey:@"catparent"]; nsstring *languagecode = [[nslocale preferredlanguages] objectatindex:0]; if ([languagecode isequaltostring:@"it"]) { cell.lblcategory.text = [cat objectforkey:@"nome_it"]; } else if ([languagecode isequaltostring:@"es"]) { cell.lblcategory.text = [cat objectforkey:@"nome_es"]; } else { cell.lblcategory.text = [cat objectforkey:@"nome_en"]; } //getting image data parse pffile pffile *theimage = [self.hh[indexpath.row] objectforkey:@"photo"]; [theimage getdatainbackgroundwithblock:^(nsdata *data, nserror *error) { if (!error) { cell.cellimageview.image = [uiimage imagewithdata:data]; } }]; //getting cell object's owner , profile pfuser *usr = [self.hh[indexpath.row] objectforkey:@"parent"]; pfquery *prof = [pfquery querywithclassname:@"profile"]; prof.cachepolicy = kpfcachepolicycachethennetwork; [prof wherekey:@"parent" equalto:usr]; [prof getfirstobjectinbackgroundwithblock:^(pfobject *object, nserror *error) { if (!error) { //getting object's rating , number of votes pfquery *ratequery = [pfquery querywithclassname:@"rating"]; [ratequery wherekey:@"parent" equalto:object]; [ratequery getfirstobjectinbackgroundwithblock:^(pfobject *object, nserror *error) { if (!error) { float vote = [[object objectforkey:@"rate"] floatvalue]; float temp = ((vote * 2) + 0.5); int tempvote = (int)temp; float roundedvote = (float)tempvote / 2; // drawing stars number, depending on rating obtained uiimage *starsimage = [uiimage imagenamed:@"stars"]; uigraphicsbeginimagecontextwithoptions(cell.imgvoto.frame.size, no, 0); cgpoint starpoint = (cgpoint) { .y = (cell.imgvoto.frame.size.height * (2 * roundedvote + 1)) - (starsimage.size.height) }; [starsimage drawatpoint:starpoint]; cell.imgvoto.image = uigraphicsgetimagefromcurrentimagecontext(); uigraphicsendimagecontext(); cell.lblvoto.text = [nsstring stringwithformat:@"(%d)", [[object objectforkey:@"voters"] intvalue]]; } }]; } }]; return cell; }
edit: cell code:
+ (void)initialize { if (self != [hh class]) { return; } } -(id)initwithcoder:(nscoder *)adecoder { if ( !(self = [super initwithcoder:adecoder]) ) return nil; self.cellimageview.image = [uiimage imagenamed:@"icona_foto"]; self.cellimageview.contentmode = uiviewcontentmodescaletofill; self.formatterdata = [[nsdateformatter alloc] init]; self.formatdata = [[nsstring alloc] init]; self.formatterora = [[nsdateformatter alloc] init]; self.formatora = [[nsstring alloc] init]; self.formatdata = [nsdateformatter dateformatfromtemplate:@"dd/mm" options:0 locale:[nslocale currentlocale]]; [self.formatterdata setdateformat:self.formatdata]; self.formatora = [nsdateformatter dateformatfromtemplate:@"j:mm" options:0 locale:[nslocale currentlocale]]; [self.formatterora setdateformat:self.formatora]; self.lblvoto.text = @"(0)"; return self; }
second edit: code in viewdidload
method:
pfquery *hours = [pfquery querywithclassname:@"hh"]; hours.cachepolicy = kpfcachepolicycachethennetwork; // here i'm making lots of query constraints i'll not include [hours findobjectsinbackgroundwithblock:^(nsarray *objects, nserror *error) { if (!error) { self.objectsnumber = objects.count; self.hh = [[nsarray alloc] initwitharray:objects]; } }]; [self.tableview reloaddata]; }
i move of logic out of cellforrowatindexpath:
can, needs light-weight scrolling performance. you're doing lot of work on main thread, , lot more of work when model objects parse (if post viewdidload
can give more specific help) , update table view when these calls done:
[uiimage imagewithdata:data]
- anything
nsdateformatter
cllocation
'sinitwithlatitude:longitude:
- creating rating stars image
none of these depend on state of table view, can precomputed , cached in model object. if scroll , down table, you're doing allo f same work on , over, killing performance.
updated questioner's newest code:
i won't include of functionality here should give idea:
// create single shared formatter instead of 1 per object nsdateformatter *dateformatter = [nsdateformatter dateformatfromtemplate:@"dd/mm" options:0 locale:[nslocale currentlocale]]; nsdateformatter *timeformatter = [nsdateformatter dateformatfromtemplate:@"j:mm" options:0 locale:[nslocale currentlocale]]; [hours findobjectsinbackgroundwithblock:^(nsarray *objects, nserror *error) { if (!error) { self.objectsnumber = objects.count; (someobject *modelobj in objects) { // if can add properties model object directly, // otherwise write category on parse object add ones need modelobj.datestring = [nsstring stringwithformat:@"%@ %@ %@ %@", modelobj.dal, [self.dateformatter stringfromdate:[modelobj objectforkey:@"startdate"]], modelobj.ore, [self.timeformatter stringfromdate:[modelobj objectforkey:@"enddate"]]]; // create locations, images, etc in here } self.hh = [[nsarray alloc] initwitharray:objects]; } }];]
then in cellforrowatindexpath:
, take precomputed properties , assign them appropriate labels, image views, etc.
it better of processing off main thread via gcd, out of scope question. see using gcd , blocks effectively more information. remember interact uikit main thread!
Comments
Post a Comment