Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/cocoa/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 奇怪的驱逐行为_Objective C_Cocoa_Caching_Memory - Fatal编程技术网

Objective c 奇怪的驱逐行为

Objective c 奇怪的驱逐行为,objective-c,cocoa,caching,memory,Objective C,Cocoa,Caching,Memory,我一直在使用NSCache来存储出于性能原因应该缓存的项,因为它们的重新创建成本相当高。不过,理解NSCache的行为让我有些头疼 我按如下方式初始化NSCache: _cellCache = [[NSCache alloc] init]; [_cellCache setDelegate:self]; [_cellCache setEvictsObjectsWithDiscardedContent:NO]; // never evict cells 缓存中的对象实现NSD

我一直在使用NSCache来存储出于性能原因应该缓存的项,因为它们的重新创建成本相当高。不过,理解NSCache的行为让我有些头疼

我按如下方式初始化NSCache:

   _cellCache = [[NSCache alloc] init];
   [_cellCache setDelegate:self];
   [_cellCache setEvictsObjectsWithDiscardedContent:NO];   // never evict cells
缓存中的对象实现NSDiscardableContent协议。现在我的问题是NSCache类在几个实例中似乎不能正常工作

1) 首先是小问题。NSCache的setCountLimit:声明:

将计数限制设置为小于或等于0的数字不会影响缓存的最大大小

有人能解释一下这意味着什么吗?也就是说,NSCache是最大的,并且仅当其他地方需要内存时才会发出丢弃内容(如果可能)消息?或者NSCache是最小的,它将立即发出丢弃内容(如果可能)消息

前者更有意义,但测试似乎表明,后者才是真正发生的事情。如果我在缓存对象中记录对DiscardContentIffailable方法的调用,我会发现它几乎是立即被调用的——在缓存中只添加了2-3打的项(每个项小于0.5 MB)之后

好的。因此,我尝试通过添加以下行来设置一个较大的计数限制(远远超出我的需要):

   [_cellCache setCountLimit:10000000];
然后,丢弃内容(如果可能)消息几乎不再立即发送。我必须将更多的内容加载到缓存中,并在这些消息开始出现之前使用一段时间,这才更有意义

那么,这里的预期行为是什么

2) 更大的问题。文件规定:

默认情况下,如果缓存中的NSDiscardableContent对象的内容被丢弃,则会自动从缓存中删除这些对象,尽管可以更改此自动删除策略。如果NSDiscardableContent对象被放入缓存中,则缓存在删除该对象时会对其调用DiscardContentIfEnabled

因此,我将逐出策略设置为NO(如上所述),以便永远不会逐出对象。相反,当调用DiscardContentIfAbsible时,我会根据特殊条件清除并释放缓存对象的内部数据。也就是说,在某些情况下,我可能决定不实际清除和丢弃数据(例如,如果该项目最近被使用)。在这种情况下,我只需从discardcontentifmably方法返回,而没有丢弃任何内容。其思想是,最近未使用的其他对象将在某个时刻获取消息,而它可以放弃其内容

现在,有趣的是,在大量使用的一段时间内,所有这些似乎都很有效。加载大量内容,在缓存中放置和访问对象,等等。但是过了一段时间,当我尝试访问NSCache中的任意对象时,它实际上不在那里!不知何故,它似乎已经被删除了——尽管我特别将驱逐政策设置为“否”

好的。因此,实现委托方法cache:willReceiveObject:表明它从未被调用。这意味着该对象实际上没有被逐出。但它正在神秘地从NSCache中消失,因为在以后的查找中找不到它——或者它所关联的密钥不再映射到原始对象。但这怎么可能发生呢

顺便说一句,我与我的值对象(CALayer)关联的键对象是一个NSURL容器/包装器,因为我不能直接使用NSURL,因为NSCache不复制键——只保留它们,并且用于查找的后续NSURL键可能不是精确的原始对象(只有相同的URL字符串)它最初用于加载带有该对象的缓存。而对于NSURL包装器/容器,我可以确保它是用于将原始值对象添加到NSCache的精确原始键对象

有人能解释一下吗?

你的评论“从不逐出单元格”不是
-setReceivesObjectswithDiscardedContent:
所说的那样。它说它不会仅仅因为内容被丢弃就驱逐细胞。这和说它永远不会驱逐细胞是两码事。您仍然可以运行超过最大大小或计数,并且它们仍然可以被逐出。可丢弃内容的优点是,您可以丢弃部分内容,而无需将自己从缓存中删除。然后,您可以根据需要重新生成丢弃的内容,但可能不必重新生成整个对象。在某些情况下,这可能是一场胜利


这就引出了你的第一个问题。是,
NSCache
在达到最大大小时开始逐出。这就是为什么它被称为“最大大小”的原因。你不会指出这是Mac还是iPhone,但在这两种情况下,你都不希望缓存增长,直到内存耗尽。这在很多方面都很糟糕。在Mac上,您将在内存耗尽之前很久就开始大量交换。在iOS中,您不希望仅仅因为某个进程的缓存太快而开始向其他每个进程发送内存警告。无论哪种情况,缓存过大都会导致性能低下。因此,放入
NSCache
的对象应该总是希望在任何时候被逐出。

感谢您的解释。看来我误解了NSCache文档。我推测,如果一个对象丢弃了内容,那么如果将其设置为NO,NSCache将不会逐出容器对象(因为此时它会有最小的内存占用)。是的,我知道缓存会一直增长,直到内存耗尽为止,这就是为什么我认为NSDiscardableContent和NSCache可以协同工作的原因。但看起来它们是独立的,尽管可以一起使用。顺便说一句,只有Mac桌面(暗示缺少与iOS相关的标签,只有Cocoa)。我认为您可以使用
NSURL
作为缓存键。我的理解是,虽然