• Stars
    star
    131
  • Rank 275,867 (Top 6 %)
  • Language
    Swift
  • License
    MIT License
  • Created over 2 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Typed key-value storage solution to store Codable types in various persistence layers with few lines of code!

๐Ÿ—‚ Stores

Stores codecov License

A typed key-value storage solution to store Codable types in various persistence layers like User Defaults, File System, Core Data, Keychain, and more with a few lines of code!

Features

  • macOS Catalina+, iOS 13+, tvOS 13+, watchOS 6+, any Linux supporting Swift 5.4+.
  • Store any Codable type.
  • Single API with implementations using User Default, file system, Core Data, Keychain, and fakes for testing.
  • Thread-safe implementations.
  • Swappable implementations with a type-erased store.
  • Modular library, add all, or only what you need.

Motivation

When working on an app that uses the composable architecture, I fell in love with how reducers use an environment type that holds any dependencies the feature needs, such as API clients, analytics clients, and more.

Stores tries to abstract the concept of a store and provide various implementations that can be injected in such environment and swapped easily when running tests or based on a remote flag.

It all boils down to the two protocols SingleObjectStore and MultiObjectStore defined in the Blueprints layer, which provide the abstract concepts of stores that can store a single or multiple objects of a generic Codable type.

The two protocols are then implemented in the different modules as explained in the chart below:

Modules chart Modules chart


Usage

Let's say you have a User struct defined as below:

struct User: Codable {
    let id: Int
    let name: String
}

Here's how you store it using Stores:

1. Conform to Identifiable

This is required to make the store associate an object with its id.

extension User: Identifiable {}

The property id can be on any Hashable type. Read more.

2. Create a store

Stores comes pre-equipped with the following stores:

  • UserDefaults
    // Store for multiple objects
    let store = MultiUserDefaultsStore<User>(suiteName: "users")
    
    // Store for a single object
    let store = SingleUserDefaultsStore<User>(suiteName: "users")
  • FileSystem
    // Store for multiple objects
    let store = MultiFileSystemStore<User>(path: "users")
    
    // Store for a single object
    let store = SingleFileSystemStore<User>(path: "users")
  • CoreData
    // Store for multiple objects
    let store = MultiCoreDataStore<User>(databaseName: "users")
    
    // Store for a single object
    let store = SingleCoreDataStore<User>(databaseName: "users")
  • Keychain
    // Store for multiple objects
    let store = MultiKeychainStore<User>(identifier: "users")
    
    // Store for a single object
    let store = SingleKeychainStore<User>(identifier: "users")
  • Fakes (for testing)
    // Store for multiple objects
    let store = MultiObjectStoreFake<User>()
    
    // Store for a single object
    let store = SingleObjectStoreFake<User>()

You can create a custom store by implementing the protocols in Blueprints

  • Realm
    // Store for multiple objects
    final class MultiRealmStore<Object: Codable & Identifiable>: MultiObjectStore {
        // ...
    }
    
    // Store for a single object
    final class SingleRealmStore<Object: Codable>: SingleObjectStore {
        // ...
    }
  • SQLite
    // Store for multiple objects
    final class MultiSQLiteStore<Object: Codable & Identifiable>: MultiObjectStore {
        // ...
    }
    
    // Store for a single object
    final class SingleSQLiteStore<Object: Codable>: SingleObjectStore {
        // ...
    }
3. Inject the store

Assuming we have a view model that uses a store to fetch data:

struct UsersViewModel {
    let store: AnyMultiObjectStore<User>
}

Inject the appropriate store implementation:

let coreDataStore = MultiCoreDataStore<User>(databaseName: "users")
let prodViewModel = UsersViewModel(store: coreDataStore.eraseToAnyStore())

or:

let fakeStore = MultiObjectStoreFake<User>()
let testViewModel = UsersViewModel(store: fakeStore.eraseToAnyStore())
4. Save, retrieve, update, or remove objects
let john = User(id: 1, name: "John Appleseed")

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

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

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

// Get an array of object in store
let users = store.objects(withIds: [1, 2, 3])

// Get an array of all objects in store
let allUsers = store.allObjects()

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

// Remove an object from a store
try store.remove(withId: 1)

// Remove multiple objects from a store
try store.remove(withIds: [1, 2, 3])

// Remove all objects in a store
try store.removeAll()

Documentation

Read the full documentation at Swift Package Index.


Installation

You can add Stores to an Xcode project by adding it as a package dependency.

  1. From the File menu, select Add Packages...
  2. Enter "https://github.com/omaralbeik/Stores" into the package repository URL text field
  3. Depending on what you want to use Stores for, add the following target(s) to your app:
    • Stores: the entire library with all stores.
    • UserDefaultsStore: use User Defaults to persist data.
    • FileSystemStore: persist data by saving it to the file system.
    • CoreDataStore: use a Core Data database to persist data.
    • KeychainStore: persist data securely in the Keychain.
    • Blueprints: protocols only, this is a good option if you do not want to use any of the provided stores and build yours.
    • StoresTestUtils to use the fakes in your tests target.

Credits and thanks


License

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

More Repositories

1

Drops

A ยตFramework for showing alerts like the one used when copying from pasteboard or connecting Apple pencil
Swift
931
star
2

UserDefaultsStore

Why not use UserDefaults to store Codable objects ๐Ÿ˜‰
Swift
449
star
3

M3UKit

Modern framework for parsing m3u files
Swift
85
star
4

StackableTableView

A UITableView subclass that enables setting an array of views for both headers and footers utilizing UIStackView
Swift
72
star
5

mnist-coreml

Simple convolutional neural network to predict handwritten digits using Keras + CoreML for WWDC '18 scholarship [Accepted]
Jupyter Notebook
54
star
6

NutritionCal

A food and nutrition app that helps you eat right and make healthier food decisions, get nutrition info for foods and drinks, keep track of what you eat, and sync your eaten foods with Apple's Health App.
Swift
33
star
7

SketchGen

A Swift command line tool for generating source code from sketch files
Swift
26
star
8

omaralbeik.com

React progressive web app backed by Django REST API
20
star
9

flaskbooks

A very light social network & RESTful API for sharing books using flask!
Python
20
star
10

making-mvc-great-again

Use generics, protocols, and extensions to get rid of massive view controllers
Swift
18
star
11

WeekdaysSegmentedControl

A Custom segmented control to select weekdays for iOS
Swift
13
star
12

ForceTouchImageView

Why pinch to zoom when you have 3D Touchย ๐Ÿค”
Swift
9
star
13

hacker-news-ios

Hacker News iOS App
Swift
8
star
14

InteractiveNavigationController

[DEPRECATED] Instagram like Custom Interactive UINavigationController with push to left and right
Swift
8
star
15

react-readable

A dynamic social application using the state management features of Redux and React
JavaScript
7
star
16

macOS-setup

The way I set up my mac after a fresh macOS install
7
star
17

VaporTodos-iOS

Simple todos app for iOS using Vapor for the backend
Swift
6
star
18

HNClient

Super easy to use client for Hacker News API
Swift
6
star
19

Spinny1

Simple yet very challenging and addictive game
Swift
5
star
20

swift-composable-architecture-todos

Simple todos app built using Swift Composable Architecture
Swift
5
star
21

MaterialPalette

Use Material Colors Palette in your XCode Project
Swift
5
star
22

BubbleView

iMessage like custom UIView
Swift
5
star
23

website-client

React progressive web app
JavaScript
5
star
24

library-finder

A single page web app, that let you find libraries near a specific place
JavaScript
4
star
25

ios-trivia

Simple trivia iOS app for demo purposes
Swift
3
star
26

VaporTodos-API

Todos API using Vapor3 and Swift4
Swift
3
star
27

UDClient

Udacity Classroom API client for iOS
Swift
2
star
28

dlnd_face_generation

A Generative Adversarial Networks to Generate new images of faces.
HTML
2
star
29

VLCKit

Umbrella repository to import VLCKit using Swift Package Manager.
Swift
2
star
30

VLCPlayer

VLC Player for SwiftUI
Swift
2
star
31

IstanbulNews

for Android Basics Nanodegree submission - an app to display latest news stories from Istanbul using the Guardians API
Java
1
star
32

MarkdownUIKit

Add markdown text to UIKit elements
Swift
1
star
33

nextcoin

Simple Next JS app
TypeScript
1
star
34

dlnd_image_classification

Project 2 for Udacity Deep Learning Nanodegree
HTML
1
star
35

nytimes-gallery

Nothing to see here, just a UICollectionView gallery example :)
Swift
1
star
36

SEN2212

Utilize binary search trees and linked-lists to search efficiently for strings in large text files
Java
1
star
37

SEN2211

SEN2211 Data Structures and Algorithms I Examples
Java
1
star
38

mlnd-titanic-survival-exploration

MLND Titanic Survival Exploration
HTML
1
star
39

dlnd_language_translation

A sequence to sequence model that can translate sentences from English to French.
HTML
1
star
40

py-blog

a multi user blog built by Python and Google App Engine.
Python
1
star
41

VLC

Install VLC using Swift Package Manager
Swift
1
star