Tips:NSCache是Foundation框架提供的緩存類的實現,使用方式類似於可變字典。由於NSMutableDictionary的存在,很多人在實現緩存時都會使用可變字典,但是NSCache在實現緩存功能時比可變字典更方便,最重要的它是線程安全的,而NSmutableDictionary不是線程安全的,在多線程環境下使用NSCache是更好的選擇。
下面是官方文檔的翻譯:
NSCache
壹個可變集合,用於臨時存儲在資源不足時容易被收回的臨時鍵值對數據。
特點:
通常使用NSCache對象來臨時存儲具有臨時數據的對象,這些臨時數據的創建成本很高。重用這些對象可以提供性能優勢,因為它們的值不必重新計算。但是,這些對象對於應用程序來說並不重要,如果內存緊張,可以丟棄它們,如果被丟棄,則必須在需要時重新計算它們的值。
如果壹個對象可以在不使用時丟棄,可以采用實現NSDiscardableContent協議來改進緩存回收行為。默認情況下,如果緩沖中的NSDiscardableContent對象的內容被丟棄,那麽它們被自動刪除,不過這個自動刪除策略可以更改。如果將NSDiscardableContent對象放入緩存,則緩存在刪除該對象時,調用discardContentlfPossible方法。
NSCache提供的屬性和相關方法:
舉個例子:
運行輸出結果:
我們可以看到當我們_cache.countLimit 設置為5的時候,添加第6-10個的時候,前面5個就會被移除了。
之後我們在把應用退出到後臺,會發現,後面5個也會被移除了:
上文中,我們提到( 如果壹個對象可以在不使用時丟棄,可以采用實現NSDiscardableContent協議來改進緩存回收行為。)並且NSCache中也有壹個屬性是 evictsObjectsWithDiscardedContent,那麽我們可以稍微了解壹下關於 NSDiscardableContent 這個協議的描述:
當壹個有內容的類的對象可以在內容不使用時丟棄,可以實現此協議,從而使應用程序占用更小的內存,這樣可以提高緩存的淘汰。
默認情況下,內存不足時,當前系統會把內存中的壹部分緩存,置換到磁盤上,所以我們使用NSDiscardableContent這個協議,把數據標記成可清除的,而不用被置換的,當沒有內容的時候,直接被清除就行了。
實現NSDiscardableContent的對象的生命周期依賴於壹個"counter"變量。
實現NSDiscardableContent的對象是壹個可清除的內存塊,它會跟蹤當前對象是否被其它對象使用。
當counter等於0時,如果內存在那個時間點吃緊,就可以丟棄當前對象。為了丟棄內容,在對象上調用discardContentIfPossible,如果counter等於0,那麽它將釋放關聯的內存。
Foundation框架包括了壹個NSPurgeableData類,該類默認實現了這個協議。
下面我們看壹下這個協議中的方法:
上面就是對於NSDiscardableContent 協議的介紹,Foundation框架中提供了壹個默認實現該協議的類:
NSPurgeableData
可以單獨使用這個對象,並不壹定和NSCache結合使用。
比如我們生成了NSPurgeableData這樣的壹個實例,並且存入到了NSCache中,然後調用endContentAccess方法,將counter設置為0,當收到內存警告的時候,NSPurgeableData的實例對象,就會被清除了。
我們使用GNUStep來看下NSCache的實現:
我們直接到setObject:forKey:方法的實現:
我們看到對象在緩存時是用的_GSCachedObject:
num也就是當前對象所占用的內存的消耗,默認是0,下面這個方法裏面,就是緩存的淘汰,我們可以看下這個方法是如何依賴num來實現具體的緩存策略:
LRU(Least recently used,最近最少使用)算法根據數據的歷史訪問記錄來進行淘汰數據,其核心思想是“如果數據最近被訪問過,那麽將來被訪問的幾率也更高”。