tl;dr You love Swift's Codable protocol and use it everywhere

Overview

Build Status Test Coverage Platforms Cocoapods Carthage compatible Swift Package Manager compatible Swift Xcode MIT

tl;dr

You love Swift's Codable protocol and use it everywhere, who doesn't! Here is an easy and very light way to store and retrieve -reasonable amount 😅 - of Codable objects, in a couple lines of code!


Introducing v2.0

  • Removed the Identifiable protocol in favor of Swift's Identifiable.
  • Increased deployment targets to iOS 13.0, tvOS 13.0, macOS 10.15, and watchOS 6.0.
  • Objects defined as non-final classes can now be used as well.
  • Added new generateSnapshot() and restoreSnapshot(_:) methods to generate and restore a Snapshot object that can be saved (e.g. to iCloud) and restored later.
  • Fixed a bug where objectsCount might run out of sync with the actual count of objects in store.

Installation

Swift Package Manager (Recommended)

You can use The Swift Package Manager to install UserDefaultsStore by adding the proper description to your Package.swift file:

import PackageDescription

let package = Package(
    name: "YOUR_PROJECT_NAME",
    targets: [],
    dependencies: [
        .package(url: "https://github.com/omaralbeik/UserDefaultsStore.git", from: "2.0.0")
    ]
)

Next, add UserDefaultsStore to your targets dependencies like so:

.target(
    name: "YOUR_TARGET_NAME",
    dependencies: [
        "UserDefaultsStore",
    ]
),

Then run swift package update.

CocoaPods

To integrate UserDefaultsStore into your Xcode project using CocoaPods, specify it in your Podfile:

pod 'UserDefaultsStore'
Carthage

To integrate UserDefaultsStore into your Xcode project using Carthage, specify it in your Cartfile:

2.0.0 ">
github "omaralbeik/UserDefaultsStore" ~> 2.0.0
Manually

Add the Sources folder to your Xcode project.

Usage

Let's say you have 2 structs; User and Laptop defined as bellow:

struct User: Codable {
    var id: Int
    var firstName: String
    var lastName: String
    var laptop: Laptop?
}
struct Laptop: Codable {
    var model: String
    var name: String
}

Here is how you store them in UserDefaultsStore:

1. Conform to the Identifiable protocol and set the id property

The Identifiable protocol lets UserDefaultsStore knows what is the unique id for each object.

struct User: Codable, Identifiable {
    ...
}
struct Laptop: Codable, Identifiable {
    var id: String { model }
    ...
}

2. Create UserDefaults Stores

(uniqueIdentifier: "laptops") ">
let usersStore = UserDefaultsStore<User>(uniqueIdentifier: "users")
let laptopsStore = UserDefaultsStore<Laptop>(uniqueIdentifier: "laptops")

3. VoilĂ , you're all set!

let macbook = Laptop(model: "A1278", name: "MacBook Pro")
let john = User(id: 1, firstName: "John", lastName: "Appleseed", laptop: macbook)

// Save an object to a store
try! usersStore.save(john)

// Save an array of objects to a store
try! usersStore.save([jane, steve, jessica])

// Get an object from store
let user = store.object(withId: 1)
let laptop = store.object(withId: "A1278")

// Get all objects in a store
let laptops = laptopsStore.allObjects()

// Check if store has an object
print(usersStore.hasObject(withId: 10)) // false

// Iterate over all objects in a store
laptopsStore.forEach { laptop in
    print(laptop.name)
}

// Delete an object from a store
usersStore.delete(withId: 1)

// Delete all objects in a store
laptops.deleteAll()

// Know how many objects are stored in a store
let usersCount = usersStore.objectsCount

// Create a snapshot
let snapshot = usersStore.generateSnapshot()

// Restore a pre-generated snapshot
try? usersStore.restoreSnapshot(snapshot)

Looking to store a single item only?

Use SingleUserDefaultsStore, it enables storing and retrieving a single value of Int, Double, String, or any Codable type.

Requirements

  • iOS 13.0+ / macOS 10.15+ / tvOS 13.0+ / watchOS 6.0+
  • Swift 5.0+

Thanks

Special thanks to:

Credits

Icon made by freepik from flaticon.com.

License

UserDefaultsStore is released under the MIT license. See LICENSE for more information.

Comments
  • Use hash value as key?

    Use hash value as key?

    Looks dangerous.

    Hash values are not guaranteed to be equal across different executions of your program. Do not save hash values to use during a future execution.

    help wanted question 
    opened by ddddxxx 5
  • Fix Codecov

    Fix Codecov

    The project has a 100% test coverage, however codecov is not working for some reason 😭 If you have an idea how to fix it, your help is highly appriciated

    help wanted 
    opened by omaralbeik 4
  • Fixed Package.swift

    Fixed Package.swift

    SPM was complaining that the directory structure didn't match up, it's usually in the format Sources/{Name}/* instead of the current Sources/*. Updated the Package.swift file to target the right directory.

    opened by terwanerik 2
  • Doesn't work with classes

    Doesn't work with classes

    After porting a bunch of code to work with UserDefaultsStore, I discovered that the "objects" you store can only be structs. It would be good to document this.

    opened by mark-anders 2
  • Release 2.1.0

    Release 2.1.0

    • Fix a bug where updating item was increasing objects count in UserDefaultsStore
    • Deprecate snapshot and custom encoder/decoder
    • Remove Jazzy in favor of DocC
    opened by omaralbeik 1
  • Not working with duplicate object

    Not working with duplicate object

    let cartSaved = UserDefaultsStore<CartItem>(uniqueIdentifier: "cart")

    When I add the same product with the same id I want to increment the quantity but the saved cart (::allObject) method return me the same product

      var cart  = getCart()
            
            var targetItem  = cart.first(where: {$0.product.id == cartItem.product.id}) // <-- targetItem is a product in the [CartItem]
                    
            
            if targetItem == nil  {
            
                print("prodct added ! ")
                cartItem.quantity += 1
                cart.append(cartItem)
                
                
            }else{
                
                targetItem?.quantity += 1
                
            }
            
            saveCart(cart: cart) // <--- here save again it should save the targetItem += 1
    
    opened by Dave181295 1
  • Bump redcarpet from 3.5.0 to 3.5.1

    Bump redcarpet from 3.5.0 to 3.5.1

    Bumps redcarpet from 3.5.0 to 3.5.1.

    Release notes

    Sourced from redcarpet's releases.

    Redcarpet v3.5.1

    Fix a security vulnerability using :quote in combination with the :escape_html option.

    Reported by Johan Smits.

    Changelog

    Sourced from redcarpet's changelog.

    Version 3.5.1 (Security)

    • Fix a security vulnerability using :quote in combination with the :escape_html option.

      Reported by Johan Smits.

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Bump json from 2.2.0 to 2.3.1

    Bump json from 2.2.0 to 2.3.1

    Bumps json from 2.2.0 to 2.3.1.

    Changelog

    Sourced from json's changelog.

    2020-06-30 (2.3.1)

    • Spelling and grammar fixes for comments. Pull request #191 by Josh Kline.
    • Enhance generic JSON and #generate docs. Pull request #347 by Victor Shepelev.
    • Add :nodoc: for GeneratorMethods. Pull request #349 by Victor Shepelev.
    • Baseline changes to help (JRuby) development. Pull request #371 by Karol Bucek.
    • Add metadata for rubygems.org. Pull request #379 by Alexandre ZANNI.
    • Remove invalid JSON.generate description from JSON module rdoc. Pull request #384 by Jeremy Evans.
    • Test with TruffleRuby in CI. Pull request #402 by Benoit Daloze.
    • Rdoc enhancements. Pull request #413 by Burdette Lamar.
    • Fixtures/ are not being tested... Pull request #416 by Marc-AndrĂŠ Lafortune.
    • Use frozen string for hash key. Pull request #420 by Marc-AndrĂŠ Lafortune.
    • Added :call-seq: to RDoc for some methods. Pull request #422 by Burdette Lamar.
    • Small typo fix. Pull request #423 by Marc-AndrĂŠ Lafortune.

    2019-12-11 (2.3.0)

    • Fix default of create_additions to always be false for JSON(user_input) and JSON.parse(user_input, nil). Note that JSON.load remains with default true and is meant for internal serialization of trusted data. [CVE-2020-10663]
    • Fix passing args all #to_json in json/add/*.
    • Fix encoding issues
    • Fix issues of keyword vs positional parameter
    • Fix JSON::Parser against bigdecimal updates
    • Bug fixes to JRuby port
    Commits
    • 0951d77 Bump version to 2.3.1
    • ddc29e2 Merge pull request #429 from flori/remove-generate-task-for-gemspec
    • cee8020 Removed gemspec task from default task on Rakefile
    • 9fd6371 Use VERSION file instead of hard-coded value
    • dc90bcf Removed explicitly date field in gemspec, it will assign by rubygems.org
    • 4c11a40 Removed task for json_pure.gemspec
    • e794ec9 Merge pull request #426 from marcandre/indent
    • 7cc9301 Merge pull request #428 from marcandre/change_fix
    • 9e2a1fb Make changes more precise #424
    • f8fa987 Merge pull request #424 from marcandre/update_changes
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 1
  • Swift PM: cannot load package

    Swift PM: cannot load package

    Cannot load package by SPM: I have used:

    ".package(url: "https://github.com/omaralbeik/UserDefaultsStore.git", from: "1.4.0")

    I have gotten: `error: dependency graph is unresolvable; found these conflicting requirements:

    Dependencies: https://github.com/omaralbeik/UserDefaultsStore.git @ 1.4.0..<2.0.0`

    opened by kalavski 1
  • Misleading docs

    Misleading docs

    Based on the documentation in the readme, I got the impression that a laptop owned by a user came from the laptop store. Meaning that what was serialized to the store was the key to the laptop and that when I retrieved a user, it would also retrieve the laptop from the store.

    What's actually happening is that the laptop is serialized into the data for the user. So if I were to say that John owned a MacBook and then changed the description of the MacBook in the laptop store, when I retrieved john's record, I would get the updated Macbook data. Instead, I get whatever was serialized when I saved john to the user store.

    Does this make sense? I think it would be good to be explicit about what's happening, because I was getting inconsistency errors based on what I thought the docs were implying.

    opened by mark-anders 1
  • JSON Encoding doesn't store JSON

    JSON Encoding doesn't store JSON

    In inspecting the plist files that are created, I was surprised to see that they're not human readable, even though a JSONEncoder is being used. The issue is that you're taking the encoding and storing that directly, rather than converting it to a string.

    I think it would be nice to have that at least as an option, to aid in debugging. To do so, you'd change save to look more like:

    	public func save(_ object: T) throws {
    		let data = try encoder.encode(object)
                    if let str = String(data: json, encoding: .utf8) {
    		     store.set(str, forKey: key(for: object))
    		     increaseCounter()
                    } else {
                         // throw appropriate error.
                    }
    	}
    
    opened by mark-anders 1
Releases(3.0.0)
Owner
Omar Albeik
It’s not a bug – it’s an undocumented feature!
Omar Albeik
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.

MindInventory 17 Sep 20, 2022
Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state.

Prephirences - Preϕrences Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, co

Eric Marchand 557 Nov 22, 2022
Swifty and modern UserDefaults

Defaults Swifty and modern UserDefaults Store key-value pairs persistently across launches of your app. It uses NSUserDefaults underneath but exposes

Sindre Sorhus 1.3k Jan 6, 2023
Simple, Strongly Typed UserDefaults for iOS, macOS and tvOS

DefaultsKit leverages Swift 4's powerful Codable capabilities to provide a Simple and Strongly Typed wrapper on top of UserDefaults. It uses less than 70 lines of code to acomplish this.

Nuno Dias 1.4k Dec 26, 2022
Zephyr synchronizes specific keys and/or all of your UserDefaults over iCloud using NSUbiquitousKeyValueStore.

Zephyr ??️ Effortlessly sync UserDefaults over iCloud About Zephyr synchronizes specific keys and/or all of your UserDefaults over iCloud using NSUbiq

Arthur Ariel Sabintsev 845 Jan 6, 2023
A library for fancy iOS animations that you will definitely love.

EazelAnimationsKit Table of Contents Introduction Animations Usage Installation Contribution Authors Introduction The drive for developing this animat

Eazel 7 Dec 13, 2022
Codable, but with Super power made custom Codable behavior easy.

Codable, but with Super power made custom Codable behavior easy.

Tsungyu Yu 24 Aug 30, 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 11, 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
An iOS app to make your love for Pokemon real.

An iOS app to make your love for Pokemon real.Which offers to make your pokemon cards live as if they were pokeballs. Each card has its own pokemon stored in it as a picturised but what if you had the powers of god to make it real and enjoyable. Don't worry now you do.Use our Poke3D and you're the god of pokemons.

Dishant Nagpal 1 Feb 27, 2022
Why not use UserDefaults to store Codable objects 😉

tl;dr You love Swift's Codable protocol and use it everywhere, who doesn't! Here is an easy and very light way to store and retrieve -reasonable amoun

Omar Albeik 452 Oct 17, 2022
CodableCloudKit allows you to easily save and retrieve Codable objects to iCloud Database (CloudKit)

CodableCloudKit CodableCloudKit allows you to easily save and retrieve Codable objects to iCloud Database (CloudKit) Features ℹ️ Add CodableCloudKit f

Laurent Grondin 65 Oct 23, 2022
Codable code is a Swift Package that allows you to convert JSON Strings into Swift structs

Codable code is a Swift Package that allows you to convert JSON Strings into Swift structs.

Julio Cesar Guzman Villanueva 2 Oct 6, 2022
iOS app for Technex, IIT(BHU) Varanasi. This project is closed before completion. You can use this app for learning purpose. You can use this app as a templet of any event related app.

technex-ios iOS app for Technex, IIT(BHU) Varanasi. This project is closed before completion for some reasons. You can use this app for learning purpo

Jogendra 12 May 9, 2022
VFNetwork is a protocol-oriented network layer that will help you assemble your requests in just a few steps.

Simple, Fast and Easy. Introduction VFNetwork is a protocol-oriented network layer that will help you assemble your requests in just a few steps. How

Victor Freitas 4 Aug 22, 2022
NSURLSession network abstraction layer, using Codable and Decodable for response and Encodable for request. ⚙️🚀

SONetworking NSURLSession network abstraction layer, using Codable and Decodable for response and Encodable for request. Project Folder and File Struc

Ahmad AlSofi 4 Jan 28, 2022
CodableCSV - Read and write CSV files row-by-row or through Swift's Codable interface.

CodableCSV provides: Imperative CSV reader/writer. Declarative CSV encoder/decoder. Support multiple inputs/outputs: Strings, Data blobs, URLs, and St

Marcos SĂĄnchez-Dehesa 369 Jan 8, 2023
Store and retrieve Codable objects to various persistence layers, in a couple lines of code!

tl;dr You love Swift's Codable protocol and use it everywhere, who doesn't! Here is an easy and very light way to store and retrieve Codable objects t

null 149 Dec 15, 2022
🌸 Powerful Codable API requests builder and manager for iOS.

This lib is about network requests with blackjack, roulette and craps! Using it you will be able to convert your massive API layer code into an awesom

CodyFire 251 Jan 8, 2023