title: Odd NSCache Eviction Behaviour
body: <p>I've been using an NSCache to store items that should be cached for performance reasons, since they are rather expensive to recreate. Understanding NSCache behaviour is giving me some headaches though.</p>
  
  <p>I initialize my NSCache as follows:</p>
  
  <pre><code>   _cellCache = [[NSCache alloc] init];
     [_cellCache setDelegate:self];
     [_cellCache setEvictsObjectsWithDiscardedContent:NO];   // never evict cells
  </code></pre>
  
  <p>The objects held in the cache implement the NSDiscardableContent protocol. Now my problem is the NSCache class does not seem to be working correctly in a couple of instances.</p>
  
  <p>1) First the smaller issue. NSCache's setCountLimit: states that:</p>
  
  <blockquote>
    <p>Setting the count limit to a number less than or equal to 0 will have no effect on the maximum size of the cache.</p>
  </blockquote>
  
  <p>Can someone shed some light on what this means? I.e., that the NSCache is maximal, and will issue <strong>discardContentIfPossible</strong> messages only when memory is  required elsewhere? Or that the NSCache is minimal, and it will issue <strong>discardContentIfPossible</strong> messages immediately? </p>
  
  <p>The former makes more sense, but testing seems to indicate that the later is what is happening. If I log calls to the <strong>discardContentIfPossible</strong> method in my cached object, I see that it is being called almost immediately -- after only a 2-3 dozen items have been added to the cache (each less than 0.5 MB).</p>
  
  <p>Okay. So I try then to set a large count limit -- way more than I will ever need -- by adding the following line:</p>
  
  <pre><code>   [_cellCache setCountLimit:10000000];
  </code></pre>
  
  <p>Then the <strong>discardContentIfPossible</strong> messages are no longer sent almost immediately. I have to load a lot more content into the cache and use it for a while before these message start occurring which makes more sense.</p>
  
  <p>So what is the intended behaviour here?</p>
  
  <p>2) The larger issue. The documentation states:</p>
  
  <blockquote>
    <p>By default, NSDiscardableContent objects in the cache are automatically removed from the cache if their content is discarded, although this automatic removal policy can be changed. If an NSDiscardableContent object is put into the cache, the cache calls <strong>discardContentIfPossible</strong> on it upon its removal.</p>
  </blockquote>
  
  <p>So I set the eviction policy to NO (as above) so objects are never evicted. Instead, when <strong>discardContentIfPossible</strong> is called, I clear and release the internal data of the cached object according to special criteria. That is, I may decide not to actually clear and discard the data under certain circumstances (for example if the item has been very recently used). In such a scenario, I simply return from the <strong>discardContentIfPossible</strong> method not having discarded anything. The idea is that some other object that isn't recently used will get the message at some point, and it can discard it's content instead.</p>
  
  <p>Now, interestingly, all seems to work great for a while of heavy use. Loading lots of content, placing and accessing objects in the cache, etc. After some time though, when I try to access an arbitrary object in the NSCache it's literally not there! Somehow it appears it has been removed -- even though I specifically set the eviction policy to NO.</p>
  
  <p>Okay. So implementing the delegate method <strong>cache:willEvictObject:</strong> shows it never gets called. Which means the object is not actually getting evicted. But it's mysteriously disappearing from the NSCache since it can't be found on future lookups -- or somehow the key it was associated with is is no longer mapped to the original object. But how can that happen?</p>
  
  <p>BTW, the key object that I'm associating with my value objects (CALayer's) is an NSURL container/wrapper, since I can't use NSURL's directly as NSCache doesn't copy keys -- only retains them, and a later NSURL key used for lookup might not be the <em>exact</em> original object (only the same URL string) that was initially used to load the cache with that object. Whereas with an NSURL wrapper/container, I can ensure it is the exact original key object that was used to add the original value object to the NSCache.</p>
  
  <p>Can anyone shed some light on this?</p>