Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/95.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 异步加载tableview单元格数据的正确方法_Iphone_Ios_Objective C_Uitableview - Fatal编程技术网

Iphone 异步加载tableview单元格数据的正确方法

Iphone 异步加载tableview单元格数据的正确方法,iphone,ios,objective-c,uitableview,Iphone,Ios,Objective C,Uitableview,我尝试异步设置UITableViewCell“description”字段,但由于重用视图单元格,当快速滚动我的tableview时出现问题-tableview单元格被刷新多次。我的代码如下。这里怎么了 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; { [TimeExecutionTracker start

我尝试异步设置
UITableViewCell
“description”字段,但由于重用视图单元格,当快速滚动我的tableview时出现问题-tableview单元格被刷新多次。我的代码如下。这里怎么了

   - (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;
    }

在您理解我的答案之前,我想告诉您以下代码不利于内存管理,因为它会为
UITableView
的每一行创建新的单元格,所以请小心

但是最好使用,当
UITableView
的行数有限时(大约50-100行),下面的代码对您的情况很有帮助。如果它适合你,就使用它

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSString *CellIdentifier = [NSString stringWithFormat:@"S%1dR%1d",indexPath.section,indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if(cell == nil)
    {
        cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

         /// Put your code here.
     }

      /// Put your code here.

    return cell;
}

如果您的行数有限,那么这是最适合您的代码。

在您按照我的答案回答之前,我想告诉您,以下代码不利于内存管理,因为它将为
UITableView
的每一行创建新的单元格,所以请小心

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSString *CellIdentifier = [NSString stringWithFormat:@"S%1dR%1d",indexPath.section,indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if(cell == nil)
    {
        cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

         /// Put your code here.
     }

      /// Put your code here.

    return cell;
}
但是最好使用,当
UITableView
的行数有限时(大约50-100行),下面的代码对您的情况很有帮助。如果它适合你,就使用它

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSString *CellIdentifier = [NSString stringWithFormat:@"S%1dR%1d",indexPath.section,indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if(cell == nil)
    {
        cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

         /// Put your code here.
     }

      /// Put your code here.

    return cell;
}
如果行数有限,则这是最适合您的代码。

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{

    NSString *CellIdentifier = [NSString stringWithFormat:@"S%1dR%1d",indexPath.section,indexPath.row];
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if(cell == nil)
    {
        cell = [[[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];

         /// Put your code here.
     }

      /// Put your code here.

    return cell;
}
dispatch_async(dispatch_get_main_queue(), ^{
    [descriptionLabel setText:[_tableViewDescirptions valueForKey:cellHash]];
});
捕获
descriptionLabel
的当前值,因此当 块时,即使该单元已被重新用于其他应用程序,也要更新该标签 同时索引路径

因此,您应该捕获单元格,并检查单元格的(当前)索引路径是否仍然等于原始(捕获的)索引路径

您还应该只在主线程上更新
\u tableviewsdescriptions
,因为它是这样的 用作数据源

这大致看起来像(未经编译器测试):

旁注:获取/设置字典值的主要方法是
objectForKey
setObject:forKey:
valueForKey:
setValue:forKey:
仅用于键值编码魔术。

dispatch_async(dispatch_get_main_queue(), ^{
    [descriptionLabel setText:[_tableViewDescirptions valueForKey:cellHash]];
});
捕获
descriptionLabel
的当前值,因此当 块时,即使该单元已被重新用于其他应用程序,也要更新该标签 同时索引路径

因此,您应该捕获单元格,并检查单元格的(当前)索引路径是否仍然等于原始(捕获的)索引路径

您还应该只在主线程上更新
\u tableviewsdescriptions
,因为它是这样的 用作数据源

这大致看起来像(未经编译器测试):

旁注:获取/设置字典值的主要方法是
objectForKey
setObject:forKey:

valueForKey:
setValue:forKey:
仅用于键值编码魔术。

我认为问题在于,只有在异步处理完成并成功时,才能填充
\u tableviewsdescriptions
(有趣的名称BTW)字典。因此,当单元格快速滚动时,您会一次又一次地设置大量异步调用

相反,始终立即设置描述(例如,使用“加载…”),并且只执行一次后台任务。下次调用此方法时,它将不会尝试再次下载。当然,如果下载失败,您需要一个后备方案

此外,我认为与其构造昂贵的字符串哈希,不如使用
indepath
作为密钥


最后,在我看来,您在后台任务中所做的工作很琐碎,并且可以很容易地在主线程中完成。

我认为问题在于,只有在异步处理完成并成功时,您才能填写
\u tableviewsdescriptions
(有趣的名称BTW)字典。因此,当单元格快速滚动时,您会一次又一次地设置大量异步调用

相反,始终立即设置描述(例如,使用“加载…”),并且只执行一次后台任务。下次调用此方法时,它将不会尝试再次下载。当然,如果下载失败,您需要一个后备方案

此外,我认为与其构造昂贵的字符串哈希,不如使用
indepath
作为密钥


最后,在我看来,您在后台任务中所做的工作很琐碎,可以很容易地在主线程中完成。

我找到了一个优雅的解决方案,只需执行以下3个步骤:


我找到了一个优雅的解决方案,只需3步(从):


请为@downVote??所有这些,我都提到过。请为@downVote??所有这些,我都提到过。