使用太多内存的UITableView中的图像

时间:2014-11-06 12:47:32

标签: objective-c uitableview

我为UITableViewCells的网址创建了一个下载图片类(在此项目中,我无法使用SDWebImageView或来自互联网的其他代码),但看起来它使用了大量内存而我的tableview加载速度不是那么快。有谁可以指出问题是什么?

代码:

//MyHelper class    
+(NSString *)pathForImage:(NSString *)urlImageString{
    if ([urlImageString class] == [NSNull class] || [urlImageString isEqualToString:@"<null>"] || [urlImageString isEqualToString:@""]) {
        return @"";
    }
    NSArray *pathsInString = [urlImageString componentsSeparatedByString:@"/"];

    NSString *eventCodeString = [pathsInString objectAtIndex:[pathsInString count] - 2];
    NSString *imageNameString = [pathsInString lastObject];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *cachePath = [paths objectAtIndex:0];

    cachePath = [MyHelper validateString:[cachePath stringByAppendingString:eventCodeString]];
    [cachePath stringByAppendingString:@"/"];

    return  [cachePath stringByAppendingString:imageNameString];
}

+(BOOL)imageExistsForURL:(NSString *)urlString{

    if (!([urlString class] == [NSNull class]))

    {
        NSString *filePath = [MyHelper pathForImage:urlString];
        NSFileManager *fileManager = [NSFileManager defaultManager];

        return [fileManager fileExistsAtPath:filePath];
    }

    return false;
}

+(void)setAsyncImage:(UIImageView *)imageView forDownloadImage:(NSString *)urlString{
    CGRect activityFrame = CGRectMake(0, 0, 60, 60);
    UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithFrame:activityFrame];
    activity.layer.cornerRadius = activity.frame.size.width / 2;
    activity.clipsToBounds = YES;

    activity.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
    [imageView addSubview:activity];
    [activity startAnimating];
    dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(concurrentQueue, ^{

        NSData *image;
        if ([urlString class] == [NSNull class]) {
            image = nil;
        } else {
            image = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:urlString]];
        }

        dispatch_async(dispatch_get_main_queue(), ^{
            [activity stopAnimating];
            [activity removeFromSuperview];
            if (image)
            {
                [UIView animateWithDuration:0.9 animations:^{
                    imageView.alpha = 0;
                    imageView.image = [UIImage imageWithData:image];
                    imageView.alpha = 1;
                }];
            NSString *filePath = [MyHelper pathForImage:urlString];
            NSError *error;
            [image writeToFile:filePath options:NSDataWritingAtomic error:&error];

            }
            else
            {
                imageView.image = [UIImage imageNamed:@"icn_male.png"];
            }
        });
    });
}

+(NSString *)validateString:(NSString *)string{
    if (string == (id)[NSNull null] || string.length == 0 )
        return @"";

    return string;
}

+ (UIImage*)imageWithImage:(UIImage*)image
              scaledToSize:(CGSize)newSize;
{
    float proportion;
    if (image.size.height > image.size.width) {
        proportion = image.size.height / newSize.height;
    } else {
        proportion = image.size.width / newSize.width;
    }

    UIGraphicsBeginImageContext( newSize );
    [image drawInRect:CGRectMake(newSize.width - (image.size.width/proportion),
                                 newSize.height/2 - (image.size.height/proportion)/2,
                                 image.size.width/proportion,
                                 image.size.height/proportion)];
    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return newImage;
}

使用此代码:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSString *cellIdentifier = @"MyCell";
    MyCell *cell = (MyCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier forIndexPath:indexPath];


    if ([MyHelper imageExistsForURL:photoURLString ]) {
        UIImage *image = [UIImage imageWithContentsOfFile:[MyHelper pathForImage:photoURLString]];
        eventImageView.image = [MyHelper imageWithImage:image scaledToSize:CGSizeMake(60, 60)];
    } else {
        [MyHelper setAsyncImage:eventImageView forDownloadImage:photoURLString ];
    }
}

1 个答案:

答案 0 :(得分:1)

由于现在很清楚您正在使用超大图像,因此解决方案是确定您的图像需要多大才能在您的应用中看起来很好。

根据您可以更改系统的服务器端部分的程度,有几种操作方法。

  • 使用最适合最高分辨率大小(3x)的图像,让2x和1x设备进行缩放。这又有点浪费。

  • 创建一些方案,您可以为您的设备类型(可能通过附加2x,3x等)获取正确大小的图像到图像文件名。可以说是最好的选择。

  • 在客户端进行调整大小。这可能是CPU密集型的,在我看来可能是最糟糕的方法,因为你将不必要地做很多工作。但是,如果您无法更改服务器的工作方式,那么这是您唯一的选择。

您的代码的另一个问题是您正在对主/ UI线程进行大小调整,这会阻止您的UI,这是禁忌。切勿在主线程上执行长时间的操作。

您应该在后台线程上使用dispatch_asyncNSOperation和一个连续队列来减少内存使用量。请注意,这可能会产生新问题,因为您必须在图像准备就绪时更新图像视图,并考虑诸如单元格是否仍然可见之类的事情。我前一段时间发现了一篇不错的博文,所以我建议在网上搜索。

但是,如果图像真的很大,那么也许您可以考虑设置代理服务器,然后从那里获取调整大小的图像而不是主服务器。当然,在这种情况下,您必须考虑知识产权问题。