本文介绍了NSCache 持有指向用 imageWithData 实例化的 UIImage 的强指针:并且在卸载时不会从内存中删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有属性 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 的强指针:并且在卸载时不会从内存中删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 19:52