9

我们在我们的应用程序中为 UIImages 使用 NSCache。这适用于小于 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被调用。从那时起,-(void)addImageToCache:(id)sender每 100 毫秒调用一次计时器。在此方法中,会生成一个 UIImage 并将其写入缓存。

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

在装有 iOS 5 和 512 MB 内存的 iPad 2 上,它也会在某些时候崩溃,但至少要经过 3000 次迭代。Instruments 显示每次发生内存警告时 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];

    }
}
4

2 回答 2

18

虽然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
于 2013-10-23T18:02:51.703 回答
3

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

NSCache 类结合了各种自动驱逐策略,确保缓存不会使用过多的系统内存。如果其他应用程序需要内存,这些策略会从缓存中删除一些项目,从而最大限度地减少其内存占用。

很可能在 iOS7 中改变了一些策略。您可以通过收听内存警告通知来删除所有内容。为了完整起见,我链接了这个答案

于 2013-10-23T15:39:00.263 回答