Vellum is local persistent data storage for iOS

Overview

Vellum

codebeat badge build test SwiftPM Compatible Version License Platform

Requirements

  • Swift 5.0 or higher
  • iOS 9.3 or higher

Installation

Cocoapods

Vellum is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'Vellum'

Swift Package Manager from XCode

  • Add it using XCode menu File > Swift Package > Add Package Dependency
  • Add https://github.com/hainayanda/Vellum.git as Swift Package URL
  • Set rules at version, with Up to Next Major option and put 1.2.3 as its version
  • Click next and wait

Swift Package Manager from Package.swift

Add as your target dependency in Package.swift

dependencies: [
    .package(url: "https://github.com/hainayanda/Vellum.git", .upToNextMajor(from: "1.2.3"))
]

Use it in your target as Vellum

 .target(
    name: "MyModule",
    dependencies: ["Vellum"]
)

Then run swift build to build the dependency before you use it

Author

Nayanda Haberty, [email protected]

License

Vellum is available under the MIT license. See the LICENSE file for more info.

Storage Algorithm

Vellum is using LRU Algorithm. It contains 2 type of storage which is Memory Storage and Disk Storage. Both sizes can be assigned manually.

Store Data

alt text

  1. Store data to Memory Storage
  2. If Memory Storage is full, it will remove the oldest accessed data from memory until space is enough for new data
  3. Data stored in the memory
  4. Store data to Disk Storage
  5. If Disk Storage is full, it will remove the oldest accessed data from memory until space is enough for new data
  6. Data stored to the disk

Getting Data

alt text

  1. Find data from the Memory Storage
  2. If the data exist, it will return the data and the step ended
  3. If the data do not exist in the memory, it will try to find data from Disk Storage
  4. If the data exist, it will store the data to the Memory Storage for future faster use and return the data and the step ended
  5. If the data do not exist, it will return nil

Usage Example

Basic Usage

All you need to do is just get the ArchiveManager from factory and store your object which implement Archivable and Codable or using typealias ArchiveCodable which is the same:

let archives = try! ArchivesFactory.shared.archives(
    for: MyArchivable.self,
    trySetMaxMemorySize: 10.megaByte, 
    trySetMaxDiskSize: 20.megaByte
)

// will insert object
archives.record(myObject)

let object = archives.access(archiveWithKey: "object_key")

Archivable

Archivable actually is just a protocol that has methods to convert an object to data or vice versa. Archivable make sure the object has keys too:

class User: Archivable {
    
    var primaryKey: String { userName }
    var userName: String = ""
    var fullName: String = ""
    var age: Int = 0
    
    func archive() throws -> Data {
        // do something to convert the object to Data
    }
    
    static func deArchive(fromData data: Data) throws -> Archivable {
        // do something to convert the data to object
    }
}

ArchiveCodable

If your object is Codable, just add Archivable or using typealias ArchiveCodable which is the same, your object will have those methods automatically. You just need to add primaryKey property you want as the primary key as long as the value is String:

struct User: Codable, Archivable {
    var primaryKey: String { userName }
    var userName: String
    var fullName: String
    var age: Int
}

ArchiveManager

To get ArchiveManager, you can use ArchivesFactory. You can assign the maximum size in bytes for memory size and disk size. But keep in mind, the size will only apply on the first creation of the ArchiveManager, If the cache manager is already created, then the memory size and disk size is ignored. If you don't assign the memory size or disk size, it will use the default value which is 1 megabyte for memory and 2 megabyte disk size:

let archives = try! ArchivesFactory.shared.archives(
    for: User.self, 
    trySetMaxMemorySize: 10.kiloByte, 
    trySetMaxDiskSize: 20.kiloByte
)

// or not explicit
let sameArchives: ArchiveManager<User> = try! ArchivesFactory.shared.archives( 
    trySetMaxMemorySize: 10.kiloByte, 
    trySetMaxDiskSize: 20.kiloByte
)

the ArchiveManager have some usable methods and property which are:

  • var maxSize: Int { get } to get maximum size of the cache
  • var currentSize: Int { get } to get current used size of the cache
  • func latestAccessedTime(for key: String) -> Date? to get the latest time the object with same key accessed
  • func deleteAllInvalidateArchives(invalidateTimeInterval: TimeInterval) to remove all object older than time interval
  • func record(_ object: Archive) to insert object
  • func update(_ object: Archive) to update existing object, or insert if have none
  • func access(archiveWithKey key: String) -> Archive? to get object with given key
  • func accessAll(limitedBy limit: Int) -> [Archive] to get all object limited by limit
  • func accessAll() -> [Archive] to get all object stored in cache
  • func delete(archiveWithKey key: String) to delete object with given key
  • func deleteAll() to remove all object from cache
  • func process(queries: [Query<Archive>]) -> [Archive] to process query. This will be disucessed later

Query

You can do a query from the cache. there are 3 types of query which are:

  • QueryFinder to find the object/results by its properties
  • QuerySorter to sort the results by its properties
  • QueryLimiter to limit the results by limit

All Query can be combined and will executed sequentially:

let results = userCache.findWhere { archive in
    archive.userName(.contains("premium"))
        .fullName(.isNotEqual(nil))
}
.getResults()

The code above will find all users in the cache whose userName contains "premium" and its fullName is not nill. The result is an array of User

let results = userCache.sorted { by in 
    by.age(.ascending)
        .fullName(.descending)
}
.getResults()

The code above will get all users in cache and sorted it by its age ascendingly and then its fullName descendingly. The results are sorted array of User

You can add the limit too

let results = userCache.sorted { by in 
    by.age(.ascending)
        .fullName(.descending)
}
.limitResults(by: 10)
.getResults()

The code above will limit the results maximum of just 10

You can even combine the query if you want:

let results = userCache.findWhere { archive in
    archive.userName(.contains("premium"))
        .fullName(.isNotEqual(nil))
}
.sorted { by in 
    by.age(.ascending)
        .fullName(.descending)
}
.limitResults(by: 10)
.getResults()

The code above will find all users in the cache whose userName contains "premium" and its fullName is not nill, then sort it by its age ascendingly and then its fullName descendingly. The results are limited by 10.

here are the list of finder that can be used with QueryFinder:

  • contains(string: ) match if string property contains given string
  • matches(regex: ) match if string property matches with given regex
  • contains(with: ) match if collection property is contains given element
  • contains(atLeastOne: ) match if collection property contains at least one of given element
  • contains(all: ) match if collection property contains all given element
  • countEqual(with: ) match if collection property count equal with given number
  • countGreater(than: ) match if collection property count greater than given number
  • countLess(than: ) match if collection property count less than given number
  • countGreaterOrEqual(with: ) match if collection property count greater than or equal with given number
  • countLessOrEqual(with: ) match if collection property count greater than or equal with given number
  • isEqual(with: ) match if property equal with given value
  • isNotEqual(with: ) match if property not equal with given value
  • greater(than: ) match if property greater than given value
  • less(than: ) match if property less than given value
  • greaterOrEqual(with: ) match if property greater than or equal with given value
  • lessOrEqual(with: ) match if property less than or equal with given value

if you want to validate manually, you can just use isValid(_ validator: (Property) -> Bool):

let results = userCache.findWhere { archive in
    archive.userName(.isValid { $0.contains("premium") })
}
.getResults()

Property Wrapper

You could use Archived property wrapper to wrapped any property so if it assigned it will automatically store those properties into ArchiveManager:

@Archived var user: User?

if you want the property to have an initial value based on the given primary key, just pass the key:

@Archived(initialPrimaryKey: "some") var user: User?

Code above will try to get the user with the given key at first property load.

You might also like...
ASDebugger is a remote debugging toolset for iOS App.

ASDebugger ASDebugger is a remote debugging toolset for iOS App. it's a way remotely check any network transaction, effortlessly Mock Data, It is able

Get more reviews in your iOS app.
Get more reviews in your iOS app.

Remotely-configurable chatbots & chat flows for iOS ChatKit is a remotely-configurable iOS library designed to help you build iMessage-esque chat flow

iOS Swift Pazarama Bootcamp Week 3 task - App by builded with iTunes Api
iOS Swift Pazarama Bootcamp Week 3 task - App by builded with iTunes Api

MeTunes! a library for itunes! MeTunes. Key Features • Installation • Download • Technologies Used • Credits • License Key Features Fully Programmatic

An Objective-C wrapper for RocksDB - A Persistent Key-Value Store for Flash and RAM Storage.

ObjectiveRocks ObjectiveRocks is an Objective-C wrapper of Facebook's RocksDB - A Persistent Key-Value Store for Flash and RAM Storage. Current RocksD

CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service.
CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service.

CloudKit, Apple’s remote data storage service, provides a possibility to store app data using users’ iCloud accounts as a back-end storage service. He

Swift Paging is a framework that helps you load and display pages of data from a larger dataset from local storage or over network.

Swift Paging is a framework that helps you load and display pages of data from a larger dataset from local storage or over network. This approach allows your app to use both network bandwidth and system resources more efficiently. It's built on top of Combine, allowing you to harness its full power, handle errors easily, etc.

Helps you easily handle Core Data's Persistent History Tracking

Persistent History Tracking Kit Helps you easily handle Core Data's Persistent History Tracking 中文版说明 What's This? Use persistent history tracking to

Realm-powered Core Data persistent store
Realm-powered Core Data persistent store

RealmIncrementalStore Realm-powered Core Data persistent store Wait, what? I like Realm. Realm's memory-mapped DB blows other databases out of the wat

StorageManager - FileManager framework that handels Store, fetch, delete and update files in local storage
StorageManager - FileManager framework that handels Store, fetch, delete and update files in local storage

StorageManager - FileManager framework that handels Store, fetch, delete and update files in local storage. Requirements iOS 8.0+ / macOS 10.10+ / tvOS

GenericLocalPersistence is a clean and easy-to-use code that is useful for integrating local storage

GenericLocalPersistence is a clean and easy-to-use code that is useful for integrating local storage like UserDefaults, PList, Keychain.

Type-safe thread-local storage in Swift
Type-safe thread-local storage in Swift

Threadly is a Swift µframework that allows for type-safe thread-local storage. What is Thread-Local Storage? Thread-local storage (TLS) lets you defin

pick the voice from the local storage.you can play and pause the voice

flutter_add_voice A new Flutter project. Getting Started This project is a starting point for a Flutter application. A few resources to get you starte

Easiest local storage library in Swift
Easiest local storage library in Swift

SundeedQLite SundeedQLite is the easiest offline database integration, built using Swift language Requirements iOS 12.0+ XCode 10.3+ Swift 5+ Installa

Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.
Easy to use cryptographic framework for data protection: secure messaging with forward secrecy and secure data storage. Has unified APIs across 14 platforms.

Themis provides strong, usable cryptography for busy people General purpose cryptographic library for storage and messaging for iOS (Swift, Obj-C), An

Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind
Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind

Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind

🛶Shallows is a generic abstraction layer over lightweight data storage and persistence.

Shallows Shallows is a generic abstraction layer over lightweight data storage and persistence. It provides a StorageKey, Value type, instances of w

Comments
  • Release 1.1.0

    Release 1.1.0

    • Added null query validator
    • Added DataSize as Int replacement
    • Added unit test for query finder
    • Added unit test for DataSize
    • Improve tryCopy() method
    • make Archived propertyWrapper to be lazy
    • remove limit results method on Archivist extensions
    opened by hainayanda 0
Releases(1.2.3)
Owner
Nayanda Haberty
Programmer. What else?
Nayanda Haberty
Cachyr A typesafe key-value data cache for iOS, macOS, tvOS and watchOS written in Swift.

Cachyr A typesafe key-value data cache for iOS, macOS, tvOS and watchOS written in Swift. There already exists plenty of cache solutions, so why creat

Norsk rikskringkasting (NRK) 124 Nov 24, 2022
Delightful framework for iOS to easily persist structs, images, and data

Installation • Usage • Debugging • A Word • Documentation • Apps Using Disk • License • Contribute • Questions? Disk is a powerful and simple file man

Saoud Rizwan 3k Jan 3, 2023
Carlos - A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps.

Carlos A simple but flexible cache, written in Swift for iOS 13+ and WatchOS 6 apps. Breaking Changes Carlos 1.0.0 has been migrated from PiedPiper de

National Media & Tech 628 Dec 3, 2022
iOS Offline Caching for Web Content

Mattress A Swift framework for storing entire web pages into a disk cache distinct from, but interoperable with, the standard NSURLCache layer. This i

BuzzFeed 522 Oct 25, 2022
A lightweight generic cache for iOS written in Swift with extra love for images.

Haneke is a lightweight generic cache for iOS and tvOS written in Swift 4. It's designed to be super-simple to use. Here's how you would initalize a J

Haneke 5.2k Dec 29, 2022
High performance cache framework for iOS.

YYCache High performance cache framework for iOS. (It's a component of YYKit) Performance You may download and compile the latest version of sqlite an

null 2.3k Dec 16, 2022
Everyone tries to implement a cache at some point in their iOS app’s lifecycle, and this is ours.

Everyone tries to implement a cache at some point in their app’s lifecycle, and this is ours. This is a library that allows people to cache NSData wit

Spotify 1.2k Dec 28, 2022
Fast, non-deadlocking parallel object cache for iOS, tvOS and OS X

PINCache Fast, non-deadlocking parallel object cache for iOS and OS X. PINCache is a fork of TMCache re-architected to fix issues with deadlocking cau

Pinterest 2.6k Dec 28, 2022
WireGuard for iOS and macOS

WireGuard for iOS and macOS This project contains an application for iOS and for macOS, as well as many components shared between the two of them. You

WireGuard 608 Dec 28, 2022
Transcription Helper - iOS application for assisting in transcribing audio files

Transcription Helper This is an iOS application written in Objective-c for assisting the people who want to work out a piece of audio, in order to wri

Soheil Novinfard 7 Oct 26, 2022