使用UIImage和下载的图像进行缓存 [英] Caching with UIImage and downloaded images

查看:46
本文介绍了使用UIImage和下载的图像进行缓存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类方法,该类方法使用完成块来获取图像.将此获取的 UIImage 用相关密钥添加到NSCache.但是,这似乎按预期工作,但是在我使用 UIImage imageWithData:方法获取图像的方法中,我发现该方法不会缓存其数据,只有 imageNamed:.

I have a class method which fetches images with a completion block. This fetched UIImage is added to an NSCache with a relevant key. This seems to work as expected, however, in the method which fetches images I am using a UIImage's imageWithData: method, which I have discovered does not cache it's data, only imageNamed: does.

我正因此而收到内存警告,这是可以理解的,如何确保不再需要用 UIImage imageWithData:方法加载的图像从内存中删除?

I am understandably getting memory warnings because of this, how do I make sure the images loaded with UIImage's imageWithData: method are removed from memory when not needed anymore?

编辑

这是下载图像的方法的代码.

Here is the code for the method which downloads the images.

- (void)imageForFootageSize:(FootageSize)footageSize withCompletionHandler:(void (^)(UIImage *image))completionBlock
{
    if (completionBlock) {
        __block UIImage *image;

        //  Try getting local image from disk.
        //
        __block NSURL *imageURL = [self localURLForFootageSize:footageSize];

        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
            image = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageURL]];

            dispatch_async(dispatch_get_main_queue(), ^{
                if (image) {
                    completionBlock(image);
                } else {
                    //
                    //  Otherwise try getting remote image.
                    //
                    imageURL = [self remoteURLForFootageSize:footageSize];

                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                        NSData *imageData = [NSData dataWithContentsOfURL:imageURL];

                        dispatch_async(dispatch_get_main_queue(), ^{
                            image = [UIImage imageWithData:imageData];

                            if (image) {
                                //
                                //  Save remote image to disk
                                //
                                NSURL *photoDirectoryURL = [Footage localURLForDirectory];

                                //      Create the folder(s) where the photos are stored.
                                //
                                [[NSFileManager defaultManager] createDirectoryAtPath:[photoDirectoryURL path] withIntermediateDirectories:YES attributes:nil error:nil];

                                //      Save photo
                                //
                                NSString *localPath = [[self localURLForFootageSize:footageSize] path];
                                [imageData writeToFile:localPath atomically:YES];
                            }

                            completionBlock(image);
                        });
                    });
                }
            });
        });
    }
}

编辑2

使用上述类方法来在完成处理程序中获取并处理 UIImage 的方法.

Methods which use the above class method to fetch and process the UIImage in the completionHandler.

UICollectionViewCell 子类中的方法.

- (void)setPhoto:(Photo *)photo withImage:(UIImage *)image
{
    [self setBackgroundColor:[UIColor blackColor]];
    [self.imageView setBackgroundColor:[UIColor clearColor]];

    if (photo && !image) {
        [photo imageForFootageSize:[Footage footageSizeThatBestFitsRect:self.bounds]
             withCompletionHandler:^(UIImage *image) {
                 if ([self.delegate respondsToSelector:@selector(galleryPhotoCollectionViewCell:didLoadImage:)]) {
                     [self.delegate galleryPhotoCollectionViewCell:self didLoadImage:image];
                 }

                 image = nil;
             }];
    }

    [self.imageView setImage:image];

    BOOL isPhotoAvailable = (BOOL)(image);

    [self.imageView setHidden:!isPhotoAvailable];
    [self.activityIndicatorView setHidden:isPhotoAvailable];
}

UICollectionView 数据源委托中的方法

Method in UICollectionView data source delegate

- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    DIGalleryPhotoCollectionViewCell *photoCell = [collectionView dequeueReusableCellWithReuseIdentifier:photoCellIdentifier forIndexPath:indexPath];

    [photoCell setDelegate:self];

    Footage *footage = [self footageForIndexPath:indexPath];
    Photo *photo = ([footage isKindOfClass:[Photo class]]) ? (Photo *)footage : nil;

    if (photo) {
        //
        //  Photo
        //
        [photoCell setPhoto:photo withImage:[self.galleryCache objectForKey:photo.footageID]];
    }

    return photoCell;
}

以下是其他相关方法:

- (void)galleryPhotoCollectionViewCell:(DIGalleryPhotoCollectionViewCell *)cell didLoadImage:(UIImage *)image
{
    NSIndexPath *indexPath = [self.galleryCollectionView indexPathForCell:cell];

    Footage *footage = [self footageForIndexPath:indexPath];

    if ([footage isKindOfClass:[Footage class]]) {
        Photo *photo = (Photo *)footage;

        UIImage *cachedImage = [self.galleryCache objectForKey:photo.footageID];

        if (!cachedImage) {
            cachedImage = image;

            [self.galleryCache setObject:image forKey:photo.footageID];
        }

        [cell setPhoto:photo withImage:image];
    }
}

还有我的 NSCache 属性 galleryCache

- (NSCache *)galleryCache
{
    if (!_galleryCache) {
        _galleryCache = [[NSCache alloc] init];
    }

    return _galleryCache;
}

推荐答案

与其使用您自己的图像下载和缓存解决方案,不如使用 SDWebImage .然后,您不必担心下载,缓存或其他任何事情. SDWebImage 也使用磁盘缓存,因此您不必担心释放内存.

Instead of rolling your own image downloading and caching solution you might be better off using SDWebImage. Then you don't have to worry about the downloading, caching or anything. SDWebImage also using disk caching so you don't have to worry about freeing memory.

SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageURL options:0 progress:^(NSInteger receivedSize, NSInteger expectedSize)
    {
        // progression tracking code
    } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
    {
        if (image)
        {
            // do something with image
        }
    }];

我不确定,但您可能还会有一个保留周期:

I'm not sure but you also might have a retain cycle:

__weak typeof(self) weakSelf = self;
[photo imageForFootageSize:[Footage footageSizeThatBestFitsRect:self.bounds] withCompletionHandler:^(UIImage *image) {
    if ([weakSelf.delegate respondsToSelector:@selector(galleryPhotoCollectionViewCell:didLoadImage:)])
    {
        [weakSelf.delegate galleryPhotoCollectionViewCell:weakSelf didLoadImage:image];
    }
    image = nil;
}];

这篇关于使用UIImage和下载的图像进行缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆