使用UIImage和下载的图像进行缓存 [英] Caching with UIImage and downloaded images
问题描述
我有一个类方法,该类方法使用完成块来获取图像.将此获取的 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
属性
- (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屋!