LRUCache is an open-source replacement for NSCache that behaves in a predictable, debuggable way

Related tags

Cache LRUCache
Overview

Build Codecov Platforms Swift 5.1 License Twitter

Introduction

LRUCache is an open-source replacement for NSCache that behaves in a predictable, debuggable way. LRUCache is an LRU (Least-Recently-Used) cache, meaning that objects will be discarded oldest-first based on the last time they were accessed. LRUCache will automatically empty itself in the event of a memory warning.

Installation

LRUCache is packaged as a dynamic framework that you can import into your Xcode project. You can install this manually, or by using Swift Package Manager.

Note: LRUCache requires Xcode 10+ to build, and runs on iOS 10+ or macOS 10.12+.

To install using Swift Package Manage, add this to the dependencies: section in your Package.swift file:

.package(url: "https://github.com/nicklockwood/LRUCache.git", .upToNextMinor(from: "1.0.0")),

Usage

You can create an instance of LRUCache as follows:

let cache = LRUCache<String, Int>()

This would create a cache of unlimited size, containing Int values keyed by String. To add a value to the cache, use:

cache.setValue(99, forKey: "foo")

To fetch a cached value, use:

let value = cache.value(forKey: "foo") // Returns nil if value not found

You can limit the cache size either by count or by cost. This can be done at initialization time:

let cache = LRUCache<URL, Date>(totalCostLimit: 1000, countLimit: 100)

Or after the cache has been created:

cache.countLimit = 100 // Limit the cache to 100 elements
cache.totalCostLimit = 1000 // Limit the cache to 1000 total cost

The cost is an arbitrary measure of size, defined by your application. For a file or data cache you might base cost on the size in bytes, or any metric you like. To specify the cost of a stored value, use the optional cost parameter:

cache.setValue(data, forKey: "foo", cost: data.count)

Values will be removed from the cache automatically when either the count or cost limits are exceeded. You can also remove values explicitly by using:

let value = cache.removeValue(forKey: "foo")

Or, if you don't need the value, by setting it to nil:

cache.setValue(nil, forKey: "foo")

And you can remove all values at once with:

cache.removeAllValues()

On iOS and tvOS, the cache will be emptied automatically in the event of a memory warning.

Concurrency

LRUCache uses NSLock internally to ensure mutations are atomic. It is therefore safe to access a single cache instance concurrently from multiple threads.

Performance

Reading, writing and removing entries from the cache are performed in constant time. When the cache is full, insertion time degrades slightly due to the need to remove elements each time a new value is inserted. This should still be constant-time, however adding a value with a large cost may cause multiple low-cost values to be evicted, which will take a time proportional to the number of values affected.

Credits

The LRUCache framework is primarily the work of Nick Lockwood.

(Full list of contributors)

You might also like...
Start your next Open-Source Swift Framework 📦
Start your next Open-Source Swift Framework 📦

SwiftKit enables you to easily generate a cross platform Swift Framework from your command line. It is the best way to start your next Open-Source Swi

Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app.
Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app.

Apphud SDK Apphud SDK is a lightweight open-source Swift library to manage auto-renewable subscriptions and other in-app purchases in your iOS app. No

Open source implementation of Apple's Combine framework for processing values over time.
Open source implementation of Apple's Combine framework for processing values over time.

OpenCombine Open-source implementation of Apple's Combine framework for processing values over time. The main goal of this project is to provide a com

Kanvas is an open-source iOS library for adding effects, drawings, text, stickers, and making GIFs from existing media or the camera.
Kanvas is an open-source iOS library for adding effects, drawings, text, stickers, and making GIFs from existing media or the camera.

Kanvas Kanvas is an open-source iOS library for adding effects, drawings, text, stickers, and making GIFs from existing media or the camera.

C4 is an open-source creative coding framework that harnesses the power of native iOS programming with a simplified API that gets you working with media right away. Build artworks, design interfaces and explore new possibilities working with media and interaction. PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture.
PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture.

PinpointKit is an open-source iOS library in Swift that lets your testers and users send feedback with annotated screenshots using a simple gesture. F

Fully open source text editor for iOS written in Swift.
Fully open source text editor for iOS written in Swift.

Edhita Fully open source text editor for iOS written in Swift. http://edhita.bornneet.com/ What Edhita means? Edhita (Romaji) == エディタ (Katakana) == Ed

SamuraiTransition is an open source Swift based library providing a collection of ViewController transitions featuring a number of neat “cutting” animations.
SamuraiTransition is an open source Swift based library providing a collection of ViewController transitions featuring a number of neat “cutting” animations.

SamuraiTransiton is a ViewController transition framework in Swift. It is an animation as if Samurai cut out the screen with a sword. transition types

KHabit an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more.

an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more. The app is completely open source, it does not contain in-app or ads, and does not track the user in any way.

Open source game built in SwiftUI and the Composable Architecture.
Open source game built in SwiftUI and the Composable Architecture.

isowords This repo contains the full source code for isowords, an iOS word search game played on a vanishing cube. Connect touching letters to form wo

an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more.

KHabit an open source, pure and minimalistic app which helps you maintain productive habits, and nothing more. The app is completely open source, it d

An open-source SwiftUI Stack Overflow client
An open-source SwiftUI Stack Overflow client

StackOv A SwiftUI Stackoverflow client We are currently in the developing process of the next version of StackOv app. The demo version of StackOv is a

Open Source project for watching YouTube channel playlists.
Open Source project for watching YouTube channel playlists.

YouTube Channel Watcher An open source project build using SwiftUI and Combine that lets you monitor a variety of different YouTube channels and their

Weathy is an Open Source Song/Musician search for Apple Music

Weathy is an Open Source Apple Music Search App You can search for Musician or Songs to play it on Apple Music / Itunes You can find the main Source i

TripUp is an open source, photo storage and sharing app made for privacy conscious users.
TripUp is an open source, photo storage and sharing app made for privacy conscious users.

TripUp is an open source, photo storage and sharing app made for privacy conscious users.

An open-source Swift framework for building event-driven, zero-config Multipeer Connectivity apps

PeerKit An open-source Swift framework for building event-driven, zero-config Multipeer Connectivity apps Usage // Automatically detect and attach to

Solana + RxSolana This is a open source library on pure swift for Solana protocol

The objective is to create a cross platform, fully functional, highly tested and less depencies as posible. The project is still at initial stage. Lots of changes chan happen to the exposed api.

An open source library for building deep-linkable SwiftUI applications with composition, testing and ergonomics in mind
An open source library for building deep-linkable SwiftUI applications with composition, testing and ergonomics in mind

Composable Navigator An open source library for building deep-linkable SwiftUI applications with composition, testing and ergonomics in mind Vanilla S

an iOS open source Radar Chart implementation
an iOS open source Radar Chart implementation

JYRadarChart an open source iOS Radar Chart implementation ##Screenshots Requirements Xcode 5 or higher iOS 5.0 or higher ARC CoreGraphics.framework D

Comments
  • Add delegate protocol

    Add delegate protocol

    I am interested in using LRUCache<String, URL> to build a file caching scheme. But it seems to me that I need a delegate which is called whenever the LRUCache removes a Value (as part of its internal operation). I.e., in my use-case, when LRUCache removes a URL, I need to be notified so I can remove the physical file the URL points to.

    I am currently running Xcode 14.0 beta and I don't understand all the Swift 5.7 changes well enough to modify LRUCache to include this delegate. Could you help??

    opened by rlaurb 6
  • Compressed/Purgeable Memory Question

    Compressed/Purgeable Memory Question

    This is more of a question / curiosity than a request to fix something.

    From past WWDCs, I remember that the advice for building memory efficient caching implementations, it is better to allow the memory to be compressed and to not evict objects during memory warnings. https://github.com/nicklockwood/LRUCache/blob/2d487e109f6d577a517682a984a1e369336eeafb/Sources/LRUCache.swift#L84

      self.token = notificationCenter.addObserver(
                forName: UIApplication.didReceiveMemoryWarningNotification,
                object: nil,
                queue: nil
            ) { [weak self] _ in
                self?.removeAllValues()
            }
    

    WWDC - https://developer.apple.com/videos/play/wwdc2018/416/?time=385

    I'm curious how one would go about supporting that? As I understand, NSCache supports this by allocating memory in a special way.

    One other note is that if you use an NSCache instead of a dictionary, that's a threat-safe way to store cached objects. And because of the way NSCache allocates its memory, it's actually purgeable, so it works even better in a memory-constrained environment. 
    

    How would one go about supporting this behavior in LRUCache? Thanks 😊

    question 
    opened by macbellingrath 2
  • Fix notifications subscription

    Fix notifications subscription

    Hi 👋

    I like idea of this simple cache 🙂

    I just came across it and realized it doesn't properly unregister from NotificationCenter. Based on documentation the token returned by addObserver(forName:object:queue:using:) the subscription doesn't end when token is deallocated, but it still needs to be unregistered (really stupid that someone in Apple thinks this is good).

    So I added unregistration to deinit and test for it 😎

    Btw. don't like that force push a moment ago 😂

    opened by olejnjak 2
  • Add subscript

    Add subscript

    Add subscript for easy access to cache:

    subscript(_ key: Key) -> Value?
    
    // usage:
    cache[key] = value
    // remove value from cache:
    cache[key] = nil
    

    Add a function overload for setValue, old function still remain to prevent source breaking change:

    // not recommended, use removeValue(forKey:) instead.
    func setValue(_ value: Value?, forKey key: Key, cost: Int)
    
    func setValue(_ value: Value, forKey key: Key, cost: Int)
    

    Reserve capacity for values when init.

    opened by danny1113 1
Releases(1.0.0)
Owner
Nick Lockwood
Nick Lockwood
A type-safe swifty wrapper around NSCache.

swift-cache A type-safe swifty wrapper around NSCache. Getting Started Add swift-cache as a dependency to your project using SPM. .package(url: "https

Binary Scraping 2 Jun 3, 2022
CachedAsyncImage is the simplest way to add cache to your AsyncImage.

CachedAsyncImage ??️ CachedAsyncImage is AsyncImage, but with cache capabilities. Usage CachedAsyncImage has the exact same API and behavior as AsyncI

Lorenzo Fiamingo 278 Jan 5, 2023
Awesome Cache Delightful on-disk cache (written in Swift). Backed by NSCache for maximum performance

Awesome Cache Delightful on-disk cache (written in Swift). Backed by NSCache for maximum performance and support for expiry of single objects. Usage d

Alexander Schuch 1.3k Dec 29, 2022
A type-safe swifty wrapper around NSCache.

swift-cache A type-safe swifty wrapper around NSCache. Getting Started Add swift-cache as a dependency to your project using SPM. .package(url: "https

Binary Scraping 2 Jun 3, 2022
Predictable state management for SwiftUI applications.

SwiftDux Predictable state management for SwiftUI applications. SwiftDux is a state container inspired by Redux and built on top of Combine and SwiftU

Steven Lambion 148 Jul 4, 2022
A simple and predictable state management library inspired by Flux + Elm + Redux.

A simple and predictable state management library inspired by Flux + Elm + Redux. Flywheel is built on top of Corotuines using the concepts of structured concurrency. At the core, lies the State Machine which is based on actor model.

Abhi Muktheeswarar 35 Dec 29, 2022
Predictable state container for Swift too

ReduxSwift ReduxSwift is a minimal Swift port of Redux, a popular JavaScript library for application state management. Functionality Centralized State

Lucas Sunsi Abreu 38 Oct 6, 2020
Redux for Swift - a predictable state container for Swift apps

Merge / deprecation announcement: ReduxKit and Swift-Flow have joined forces! The result is ReSwift. The nitty gritty: We decided to deprecate ReduxKi

null 613 Jan 3, 2023
A replacement for as which runs in constant time instead of O(n) when the conformance is not satisfiedA replacement for as which runs in constant time instead of O(n) when the conformance is not satisfied

ZConform A replacement for as? which runs in constant time instead of O(n) when the conformance is not satisfied. How it works ZConform does a one-tim

Emerge Tools 20 Aug 4, 2022
NP-Open-House-Setup - Automated setup utility and instructions for Friction booth at NP Open House 2022

Friction Setup Setup Instructions Friction setup Start up the iMac Give it a cou

Jia Chen 0 Jan 4, 2022