达到内存限制时NSCache崩溃(仅限iOS 7)

时间:2013-10-23 15:32:05

标签: objective-c memory ios7 nscache

我们在我们的应用程序中使用NSCache进行UIImages。这适用于小于7的iOS版本。当发生内存警告时,NSCache会按预期释放对象。 但是,在iOS 7上,我们的应用程序在第一次内存警告后不久崩溃。因此,似乎从未发布与NSCache一起存储的对象,但缓存正在增长,直到应用程序崩溃。用仪器进行分析证实了这种怀疑。

其他人是否遇到此问题,您是否找到了解决方法或已经跟踪过错误?

看起来这些人有同样的问题:http://www.photosmithapp.com/index.php/2013/10/photosmith-3-0-2-photo-caching-and-ios-7/

我创建了一个小样本应用来说明问题。按下按钮时,将调用方法-(IBAction)fillCache:(id)sender。从那时起,计时器每100毫秒调用-(void)addImageToCache:(id)sender。在此方法中,生成UIImage并将其写入缓存。

在带有iOS 7.0.3及其512 MB内存的iPad Mini上,它在大约350次迭代后崩溃。

在具有iOS 5和512 MB内存的iPad 2上,它也会在某些时候崩溃,但仅在至少3000次迭代后崩溃。仪器显示每次发生内存警告时,UIImage实例的数量会减少。在iOS 7上情况并非如此。

- (IBAction)fillCache:(id)sender
{
    [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(addImageToCache:) userInfo:nil repeats:YES];
}

- (void)addImageToCache:(id)sender
{
    @autoreleasepool {

        CGRect rect = CGRectMake(0, 0, 500, 500);
        UIGraphicsBeginImageContextWithOptions(rect.size, NO, 0);
        UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();

        NSString *poolKey = [NSString stringWithFormat:@"junk_%d", count++];
        [self.cache setObject:image forKey:poolKey];

    }
}

2 个答案:

答案 0 :(得分:16)

虽然NSCache从未对内存警告做出响应,但我发现它通常会对真正的内存压力做出反应。无法响应内存警告一直是一种烦恼(例如,你不能只使用“模拟内存警告”来测试应用程序在内存压力下的行为)。

话虽如此,我看到你描述的行为相同。 iOS 7似乎改变了NSCache行为。

就个人而言,我只有简单的NSCache子类,只是在收到UIApplicationDidReceiveMemoryWarningNotification通知后删除所有对象:

@implementation AutoPurgeCache

- (id)init
{
    self = [super init];
    if (self) {
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(removeAllObjects) name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
    }
    return self;
}

- (void)dealloc
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil];
}

@end

答案 1 :(得分:3)

NSCache对象根据自己的规则删除其数据。这并不意味着它会在记忆警告期间释放内容 这里的文件说明了:

  

NSCache类包含各种自动驱逐策略   确保缓存不会占用太多的系统内存。如果   其他应用程序需要内存,这些策略会删除一些内存   来自缓存的项目,最小化其内存占用。

最有可能改变了iOS7中的一些策略。您可以通过收听内存警告通知来删除所有内容。为了完整起见,我将此answer链接起来。