【问题标题】:Images changes in tableview after every scroll每次滚动后表格视图中的图像都会发生变化
【发布时间】:2013-12-04 05:25:20
【问题描述】:

嗨,我对 IOS 很陌生,所以请原谅愚蠢的问题。我正在开发一个在表格视图中加载大图像的应用程序。我正在异步获取本地图像并将其存储到字典中以进行缓存强>
这是我的代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:
(NSIndexPath *)indexPath {
        static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell =
        (UITableViewCell *) [tableView dequeueReusableCellWithIdentifier:CellIdentifier];

    if (cell == nil) {
        cell =
            [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
                                   reuseIdentifier:CellIdentifier];
    }
      NSError *attributesError = nil;

    NSString *workSpacePath = [[self applicationDocumentsDirectory]
                            stringByAppendingPathComponent:[images objectAtIndex:indexPath.row]];
    NSDictionary *fileAttributes = [[NSFileManager defaultManager]
                                 attributesOfItemAtPath:workSpacePath error:&attributesError];
    NSNumber * fileSizeNumber = [fileAttributes objectForKey:NSFileSize];
    long long int fileKBSize = [fileSizeNumber longLongValue]/1024;

   cell.textLabel.backgroundColor = [UIColor clearColor];
    NSString *descriptionString =  [images objectAtIndex:indexPath.row];
    NSLog(@"descriptionString :%@",descriptionString);
    if ([[despDectionary objectForKey:descriptionString] length] > 0) {
            cell.detailTextLabel.text = [NSString stringWithFormat:@"%@",[despDectionary objectForKey:descriptionString]];
    }
    else {
            cell.detailTextLabel.text = @"File Description";
    }

    if([self.cacheImages objectForKey:descriptionString]!=nil)
    {
     cell.imageView.image = [self.cacheImages valueForKey:descriptionString];
    }

    else
    {
    dispatch_queue_t bg = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);

    dispatch_async(bg,^{

    UIImage *myimage=[UIImage imageWithData:[NSData dataWithContentsOfFile:workSpacePath]];

   NSData *imageData = UIImageJPEGRepresentation(myimage, 0.2);
    UIImage *image = [UIImage imageWithData:imageData];
    UIImage *thumb = [image makethumbnail:CGSizeMake(110, 70)];
    dispatch_async(dispatch_get_main_queue(), ^{
   // [cell.setNeedsLayout];
     cell.imageView.frame = CGRectMake(0, 0, 110, 70);
    if([tableView indexPathForCell:cell].row== indexPath.row)
    {
    //cell.imageView.frame = CGRectMake(0, 0, 110, 70);
    NSString *imagename = [NSString stringWithFormat:@"%@",[despDectionary objectForKey:descriptionString]];
     [self.cacheImages setValue:thumb forKey:imagename];
           cell.imageView.frame = CGRectMake(0, 0, 110, 70);
      NSLog(@"cacheImages -- %@",self.cacheImages);
    cell.imageView.image = [self.cacheImages valueForKey:imagename];
   // [tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
    }//[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
      });
    });
  }
  // NSLog(@" Dictionary CACHE IMAGES is @%",self.cacheImages);
    cell.detailTextLabel.backgroundColor = [UIColor clearColor];
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
    button.frame = CGRectMake(250, 0, 49,56);
    [button setImage:[UIImage imageNamed:@"deletButotn.png"] forState:UIControlStateNormal];
    button.tag = indexPath.row;
    [button addTarget:self action:@selector(deleteButtonAction:)  forControlEvents:UIControlEventTouchUpInside];
    [cell.contentView addSubview:button];


    return  cell;
} 

【问题讨论】:

  • 感谢您的回复,但我使用的是本地图像而不是网络图像,我猜 SDWebImage 是用于网络图像的
  • 您最终找到解决调整大小问题的方法了吗?

标签: ios multithreading uitableview asynchronous


【解决方案1】:

使用直接存储图像的NSCacheNSDictionary - 特别是如果您使用它异步是非常昂贵的。您可以使用Instruments Profile 您的应用程序,并查看是否存在内存泄漏或分配问题。我认为您可能遇到了太多分配问题。

作为一种解决方案,我建议您使用NSDictionaryNSCache 来存储不是图像而是图像路径。您还可以使用NSOperation 从存储在缓存变量中的路径获取图像。顺便说一句,您将异步获取图像。

例如,创建了一个ImageRecord 类,其中包括图像路径imageID。在那个类中,我们有一个从磁盘获取图像的函数。虽然可以异步调用该函数或作为 NSOperation 调用该函数:

@implementation ImageRecord

NSString *filePath;
NSString *imageID;
// Ignoring getters, setters and other functions

// Here is our function :
-(UIImage *)getImageFromDisk{
    UIImage *image = [UIImage new];
    NSData *data = [NSData dataWithContentsOfMappedFile:self.filePath];
    if (data) {
        image = [UIImage imageWithData:data];
        if (!image) {
            return nil;
        }
    }
    return image;
}

在 cellForRowAtIndexPath 函数中:

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

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
    // example caching variable: We have a list of imageRecords with ID's and filePaths 
    // We're using indexPath as imageID of imageRecord
    imagesCache = (NSDictionary *) [self getImagesCache]
    ImageRecord *aRecord = [imagesCache objectForKey:indexPath.row];
    // I didn't call directly but you can try to call the function asynchronously.
    cell.imageView.image  = [aRecord getImageFromDisk];
    return cell;
}

会有语法错误,我很抱歉,但我希望示例的逻辑对您克服问题有所帮助

【讨论】:

    【解决方案2】:

    我建议使用 SDWebimage 来管理这个...如此简单和一致。

    https://github.com/rs/SDWebImage

    【讨论】:

    • SDWebimage 不是用于 web 图像吗?我正在处理本地图像,例如将相机拍摄的图像添加到 tableview
    • 我明白了,是的,它适用于网络图像......然后你的问题是你没有调度到 main_queue.. 阅读这个.. 我不确定滞后,也许你可以检查一下 NSCache,它在这种情况下会很方便......我能帮你更多吗?
    • 非常感谢您的回复 Mr_bem。我正在调度主队列,你能推荐一些在这种情况下实现 NSCache 的教程吗?
    • 没问题!对不起!没有看到 main_queue 调度!那么也许滞后是在那里造成的,只有在你想更新视图时才调度,这是最好的做法。但是,您可以像使用 NSDictionary 一样使用 NSCache,只需更改类型即可。它在低级别进行自我管理,但那里的数据不会永远保留,它们会在不需要时自动释放。检查它的文档,无非是使用中的字典 ;D 还有什么?
    • 我将其更改为 NSCache .. 问题仍然存在 :(
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多