iphone - Correct way to asynchronously load tableview cell data -
i try asynchronously set uitableviewcell
'description' field, due reusing view cells have problems when fast scroll tableview - tableview cells refreshed several times. code below. what's wrong here?
- (uitableviewcell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath; { [timeexecutiontracker starttrackingwithname:@"cellforrowatindexpath"]; static nsstring *cellidentifier = @"messagecell"; uitableviewcell *cell = [tableview dequeuereusablecellwithidentifier:cellidentifier]; if (cell == nil) { cell = [[uitableviewcell alloc] initwithstyle:uitableviewcellstyledefault reuseidentifier:cellidentifier]; } ctcoremessage *message = [_searchresults objectatindex:indexpath.row]; uilabel *fromlabel = (uilabel *)[cell viewwithtag:101]; uilabel *datelabel = (uilabel *)[cell viewwithtag:102]; uilabel *subjectlabel = (uilabel *)[cell viewwithtag:103]; uilabel *descriptionlabel = (uilabel *)[cell viewwithtag:104]; [subjectlabel settext:message.subject]; [fromlabel settext:[message.from tostringseparatingbycomma]]; [datelabel settext:[nsdateformatter localizedstringfromdate:message.senderdate datestyle:nsdateformattershortstyle timestyle:nil]]; nsstring *cellhash = [[nsstring stringwithformat:@"%@%@%@",fromlabel.text,datelabel.text,subjectlabel.text] md5]; if([_tableviewdescirptions valueforkey:cellhash] == nil){ [descriptionlabel settext:@"loading ..."]; dispatch_async(backgroundqueue, ^{ bool ishtml; nsstring *shortbody = [message bodypreferringplaintext:&ishtml]; shortbody = [shortbody substringtoindex: min(100, [shortbody length])]; [_tableviewdescirptions setvalue:shortbody forkey:cellhash]; dispatch_async(dispatch_get_main_queue(), ^{ [descriptionlabel settext:[_tableviewdescirptions valueforkey:cellhash]]; }); }); }else{ [descriptionlabel settext:[_tableviewdescirptions valueforkey:cellhash]]; } [timeexecutiontracker stoptrackingandprint]; return cell; }
the block
dispatch_async(dispatch_get_main_queue(), ^{ [descriptionlabel settext:[_tableviewdescirptions valueforkey:cellhash]]; });
captures current value of descriptionlabel
, therefore, when block executed, update label if cell has been reused different index path in meantime.
you should therefore capture cell instead, , check if cell's (current) index path still equal original (captured) index path.
you should update _tableviewdescirptions
on main thread, used data source.
this (not compiler tested):
dispatch_async(dispatch_get_main_queue(), ^{ [_tableviewdescirptions setvalue:shortbody forkey:cellhash]; if ([[tableview indexpathforcell:cell] isequal:indexpath]) { uilabel *descriptionlabel = (uilabel *)[cell viewwithtag:104]; [descriptionlabel settext:[_tableviewdescirptions valueforkey:cellhash]]; } });
side note: primary methods get/set dictionary values objectforkey
, setobject:forkey:
. valueforkey:
, setvalue:forkey:
used key-value coding magic.
Comments
Post a Comment