问题描述
我有一个带有属性 galleryCache
的视图控制器,当使用 GCD 和 imageWithData:
下载图像时,图像会通过密钥成功添加到缓存中.然而,当视图控制器被解散时,它会保留指向那些下载图像的强指针,导致它们不会从内存中删除.即使我在 viewDidDisappear:
内存中的缓存上使用 removeAllObjects
方法也不会清除.
I have a View Controller with a property galleryCache
and when an image is downloaded using GCD and imageWithData:
the image is added to the cache successfully with a key. However, when the view controller is dismissed it keeps strong pointers to those downloaded images causing them not to be removed from memory. Even if I use the removeAllObjects
method on the cache in viewDidDisappear:
memory does not clear up.
有人知道为什么会这样吗?
Does anyone know why this might be?
这是下载图像的方法的代码.
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);
});
});
}
});
});
}
}
使用上述类方法在completionHandler中获取和处理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
数据源委托中的方法
- (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
属性的 getter 方法 galleryCache
And also my getter method for the NSCache
property galleryCache
- (NSCache *)galleryCache
{
if (!_galleryCache) {
_galleryCache = [[NSCache alloc] init];
}
return _galleryCache;
}
编辑
这是 Instruments 的快照,显示了 NSCache 的所有者(视图控制器)被解散后的保留计数历史记录.
Here is a snapshot of Instruments showing the retain count history of one of the NSCache once its owner (a View Controller) is dismissed.
推荐答案
好的,所以在重新检查我自己的代码并重新检查第 10 亿 xn 次的属性后,我发现我的错误是将委托属性分配为强' 类型.经验教训:始终将委托设置为 WEAK.
OK, so after re examining my own code and re examining properties for the billionth x n time, it turns out my error was assigning the delegate property as a 'strong' type. Lesson learned: ALWAYS set delegates as WEAK.
不过,我肯定需要更多地了解 Instruments.
I will definitely have to learn more about Instruments, however.
这篇关于NSCache 持有指向用 imageWithData 实例化的 UIImage 的强指针:并且在卸载时不会从内存中删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!