A caching and consistency solution for immutable models.

Related tags

Cache RocketData
Overview

🚀 Data

Build Status codecov GitHub release CocoaPods

Rocket Data is a model management system with persistence for immutable models.

Motivation

Immutability has many benefits, but keeping models consistent and making changes is difficult. This library manages the consistency and caching of immutable models. It is intended to be an ideal replacement for Core Data. However, unlike Core Data, it does not block the main thread and does not crash whenever you do something slightly incorrect (see Core Data Comparison). In most setups, the backing cache does not need a schema, and you never need to add migration logic.

Scale

Rocket Data scales extremely well to large numbers of models and data providers. Since it does nearly all of its work on a background thread, you never need to worry about one change slowing down the whole application. You can also choose to stop listening to changes when a view controller is off screen to further increase performance.

The library is optimized for applications that fetch data from an external source, display it on the device, and allow the user to perform actions on this data. It implements an easy model for synchronizing this data in-memory between view controllers and with the cache.

Bring Your Own Cache

With Rocket Data, you can choose your own caching solution. We recommend a fast key-value store, but you can use any store you can imagine. This also makes it easy to add LRU eviction.

Installation

Installation via both CocoaPods and Carthage is supported.

CocoaPods

Add this to your Podspec:

pod 'RocketData'

Then run pod install.

Carthage

Add this to your Cartfile:

github "plivesey/RocketData"

Then run carthage update RocketData --platform ios

NOTE: Currently, --platform ios is necessary for some reason. We are investigating the issue.

Swift Version

We are currently not maintaining separate branches for different Swift versions. You can use an older version of Rocket Data for older versions of Swift though. HEAD currently supports Swift 4.2.

Swift Version Rocket Data Version
1 Not supported
2.0 - 2.1 1.x.x (untested)
2.2 1.x.x
2.3 (Cocoapods) 1.x.x
2.3 (Carthage) 1.2.0
3 (Easy migration API) 2.0.0
3 (Better API) 4.x.x
4 5.x.x
4.2 7.x.x

NOTE: If you are migrating to Swift 3, consider using version 2.0.0 first, then migrating to 3.x.x. 3.0.0 migrates the code to the new syntax without making any API changes. 3.x.x introduces a better API which is more consistent with the new Swift 3 API guidelines.

Documentation

To get started, you should take a look at the docs.

Consistency Manager

Rocket Data uses ConsistencyManager to manage the in-memory consistency of models. While you never need to access the Consistency Manager directly, understanding how it works will help you understand Rocket Data.

Comments
  • DataProviders don't call delegate for update after first miss?

    DataProviders don't call delegate for update after first miss?

    Hey, thanks for a great library. I was trying to integrate it into my project. I use a wrapper ReactiveProvider<T> around DataProvider<T> for RAC Support. I have my ReactiveProviders in each viewModel, but networking is done elsewhere so I initiate another DataProvider and call setData(_:updateCache:context:) on that data provider, and the ReactiveProvider doesn't get the delegate call for update.

    Is this expected behaviour? I saw another issue, is this related to that? https://github.com/linkedin/RocketData/issues/8

    Here is the code for ReactiveProvider

    class ReactiveProvider<M: SimpleModel> {
        private let provider = DataProvider<M>()
    
        let signal: Signal<M?, NoError>
        fileprivate let pipe: Observer<M?, NoError>
    
        init() {
            let (signal, pipe) = Signal<M?, NoError>.pipe()
            self.signal = signal
            self.pipe = pipe
            provider.delegate = self
        }
    
        func start(with cacheKey: CacheKey) {
            if provider.isPaused {
                provider.isPaused = false
            }
            provider.fetchDataFromCache(withCacheKey: cacheKey.key, context: cacheKey) {
                [weak self] model, error in
                self?.pipe.send(value: model)
            }
        }
    
        func pause() {
            provider.isPaused = true
        }
    }
    
    extension ReactiveProvider: DataProviderDelegate {
        func dataProviderHasUpdatedData<T>(_ dataProvider: DataProvider<T>,
                                        context: Any?) {
            guard let data = dataProvider.data as? M else {
                pipe.send(value: nil)
                return
            }
    
            pipe.send(value: data)
        }
    }
    

    and here is the code that sets the data (in networking part of the app, not in viewModel)

    class CacheProvider {
        private var providers: [String: Any] = [:]
    
        func cache<T: SimpleModel>(object: T?, for key: CacheKey) {
            let provider: DataProvider<T>
            if let p = providers[key.key] as? DataProvider<T> {
                provider = p
            } else {
                provider = DataProvider<T>()
                providers[key.key] = provider
            }
            provider.setData(object, updateCache: true, context: key)
        }
    }
    
    opened by akaralar 42
  • Support Carthage

    Support Carthage

    This commit adds a Cartfile that specifies the dependency to ConsistencyManager-iOS. The pull request is depending on the ConsistencyManager-iOS-PR-32 which provides better Carthage support.

    For now, I've specified any version of the consistency manager compatible with 2.0.0 but you should better specify the next (minor?) release version that contains the PR listed above (s.th. like 2.0.1 but that's up to you and how you like to version).

    If you want, I could also add installation instructions for Carthage to the Readme.

    Thanks!

    opened by floriankrueger 12
  • Error

    Error "Couldn't find platform in Info.plist CFBundleSupportedPlatforms or binary for ConsistencyManager"

    Hello,

    I'm encountering the following error when trying to install RocketData through Carthage in a brand new project. It's basically an empty folder with github "linkedin/RocketData" defined in a Cartfile.

    2016-10-24 11:42:10.277 xcodebuild[74733:2842940] [MT] DVTAssertions: Warning in /Library/Caches/com.apple.xbs/Sources/IDEFrameworks/IDEFrameworks-11246/IDEFoundation/Execution/RunDestinations/IDERunDestination.m:201 Details: Unable to find platform for /Users/plivesey/Library/Developer/Xcode/DerivedData/ConsistencyManager-ezmcupkggqbxrkawtipbzcwqqolg/Build/Products/ConsistencyManager: Error Domain=DVTFoundationNSBundleAdditionsErrorDomain Code=1 "Couldn't find platform in Info.plist CFBundleSupportedPlatforms or binary for ConsistencyManager" UserInfo={NSLocalizedDescription=Couldn't find platform in Info.plist CFBundleSupportedPlatforms or binary for ConsistencyManager} Function: DVTPlatform *_IDEPlatformForPathRunnable(IDEPathRunnable *__strong) Thread: <NSThread: 0x7fa5afd13660>{number = 1, name = main} Please file a bug at http://bugreport.apple.com with this warning message and any useful information you can provide.

    opened by elimist 11
  • Crash: DataProvider.swift line 92 DataProvider.init(dataModelManager : DataModelManager) -> DataProvider<A>

    Crash: DataProvider.swift line 92 DataProvider.init(dataModelManager : DataModelManager) -> DataProvider

    Hey, I have started using Rocket Data recently and faced this crash. Please help me to identify what is this issue:-

    #0. Crashed: com.apple.main-thread
    0  libswiftCore.dylib             0x1089ae5f0 swift_storeEnumTagSinglePayload + 36
    1  RocketData                     0x107d3addc DataProvider.init(dataModelManager : DataModelManager) -> DataProvider<A> (DataProvider.swift:92)
    2  HDCommons                      0x104b08bdc DataProvider.init() (CacheContextUtils.swift:38)
    3  HDCommons                      0x104b07818 CaheContext.__allocating_init() (CacheContext.swift:87)
    4  HDCommons                      0x104b0a75c specialized CachedAttributes.save<A>(value:) (CachedAttributes.swift:16)
    5  ABCApp                        0x102845d68 specialized PatientConfigUsecase.(getConfig(parameters : [String : Any]?) -> Promise<PatientConfig>).(closure #1).(closure #1) (PatientConfigUsecase.swift:82)
    6  ABCApp                        0x10284133c partial apply for PatientConfigUsecase.(getConfig(parameters : [String : Any]?) -> Promise<PatientConfig>).(closure #1).(closure #1) (PatientConfigUsecase.swift)
    7  ABCApp                        0x1028413a0 DataResponse<PatientConfig> (PatientConfigUsecase.swift)
    8  Alamofire                      0x102dae8fc closure #1 in closure #1 in DataRequest.response<A>(queue:responseSerializer:completionHandler:) + 156
    9  Alamofire                      0x102db2a8c partial apply for closure #1 in closure #1 in DownloadRequest.response<A>(queue:responseSerializer:completionHandler:) + 44
    10 Alamofire                      0x102d8e4c0 _T0Ieg_IeyB_TR (NetworkReachabilityManager.swift)
    11 libdispatch.dylib              0x200dff6c8 _dispatch_call_block_and_release + 24
    12 libdispatch.dylib              0x200e00484 _dispatch_client_callout + 16
    13 libdispatch.dylib              0x200ddfb44 _dispatch_main_queue_callback_4CF$VARIANT$armv81 + 1012
    14 CoreFoundation                 0x2013561bc __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 12
    15 CoreFoundation                 0x201351084 __CFRunLoopRun + 1964
    16 CoreFoundation                 0x2013505b8 CFRunLoopRunSpecific + 436
    17 GraphicsServices               0x2035c4584 GSEventRunModal + 100
    18 UIKitCore                      0x22e348bc8 UIApplicationMain + 212
    19 ABCApp                        0x1027a5c54 main (AppDelegate.swift:69)
    20 libdyld.dylib                  0x200e10b94 start + 4
    
    
    
    opened by balrajOla 10
  • Notifying CollectionDataProvider of updates in a child model

    Notifying CollectionDataProvider of updates in a child model

    Here's what I am struggling to get my head around. Suppose we have these models

    struct User: Model {
        let id: Int
        let online: Bool
    }
    
    struct Message: Model {
       let id: Int
       let user: User
    }
    

    and CollectionDataProvider<Message>() in a view controller. AFAIU, Consistency manager only notifies CollectionDataProviderDelegate if CollectionDataProvider has been updated via set setData(). So far, so good.

    Now I want my view controller to be notified if User model has been updated from somewhere else. As described here: https://github.com/plivesey/ConsistencyManager-iOS/#how-it-works

    There seem to be no method listenForUpdates(self) in Consistency Manager. I presume it was replaced with addListener. But it sounds like I shouldn't use CM directly, because Rocket Data does it for us. The way it is done in my understanding is via DataProvider. Now in the example individual Message models are provided by CollectionDataProvider already. What is the correct approach to listen to User model updates, so that a corresponding Message can be refreshed in the view controller?

    1. Creating a new DataProvider for each Message from the collection?
    2. Creating a DataProvider for User in each Message?
    3. Adding a listener using ConsistencyManager directly?

    This scenario is mentioned in Peter's presentation and somewhere else, but I couldn't find a proper example or figure this out. Thanks.

    opened by dyahns 9
  • improve performance when has data conflicts

    improve performance when has data conflicts

    In this pr, i do 2 things. The first one, I adapte the swift4 syntax to eliminate the warnings. The second one is performance improvement. Performance improvement as follow, when called dataHolder.setData(data, changeTime: ChangeTime()) method, if method return directly because of the conflict resolution mechanism,and code logic will continue to write data to the cache. In this case, it is unnecessary.

    opened by elijahdou 8
  • Support for Swift 3.0

    Support for Swift 3.0

    Hey, I noticed that you guys are actively adding Swift 3 support for ConsistencyManager-iOS.

    Are you planning on adding Swift 3 support for RocketData? Do you need help with that? Or do you recommend using ConsistencyManager directly?

    opened by NinoScript 8
  • Find or Create when saving data in cache

    Find or Create when saving data in cache

    Hey there!

    How can I ensure that every model is referencing a copy of the cached data?

    For example, imagine Twitter, where each Tweet has a User.

    struct Tweet {
      let id: String
      let user: User
    }
    
    struct User {
      let id: String
      let someRandomString = String.random() // For example purposes. :)
    }
    

    Now when importing from the API, each Tweet in the API response has a copy of its User, but on the iOS client we add a generated property (e.g. someRandomString) and cache this generated property. Every copy of User, even if they have the same modelIdentifier, will have a very different someRandomString value upon import since the value does not come from the server. Is there any way to "find or create" this data smartly?

    So far I see two options:

    1. Every time I create a user, fetch the copy in the cache manually and set someRandomString from cache without setting it locally. This is problematic since modelFromCache is async.
    2. Call updateModel on the DataModelManager which will then let all instances of CollectionDataProvider know that a change has been made and to update from the cache (which will then force all copies of User to sync.)

    Any other options/ideas?

    opened by jamescmartinez 7
  • ConsistencyManager 5.1 and Cocoapods

    ConsistencyManager 5.1 and Cocoapods

    Can you please do a new release for Cocoapods to update ConsistencyManager to the latest version? Version 5.1 has an important update, without it there is a crash in Swift 4.

    opened by Vortec4800 6
  • Is there a way to wipe all models from both cache and memory?

    Is there a way to wipe all models from both cache and memory?

    Hey,

    When a user logs out, I want to wipe everything so that cached items don't leak into the next session. I went through the docs but couldn't make out if this was supported?

    opened by akaralar 6
  • Example CacheDelegate implementations

    Example CacheDelegate implementations

    When trying to start using this, you(me) get in the weeds pretty quick as you need to implement your own caching layer to begin using this.

    It would be great if there was an example or few cache delegate implementations to reference or use to help people get started quicker. 😎

    opened by jakecraige 6
  • Catalyst compatibility

    Catalyst compatibility

    I see theres a note in the readme saying that currently only iOS platform is compiling for carthage. Is the reason already known? and is this being worked on? Besides that, any reason it wouldn't be compatible with mac catalyst? Thanks

    opened by heitorfr 1
  • Add SwiftUI support

    Add SwiftUI support

    It should be trivial to make data providers observable objects. Since the library promotes a one way data flow anyway, using it with SwiftUI seems natural.

    opened by plivesey 0
  • Example App with complex models

    Example App with complex models

    Has anyone implemented RocketData with complex models and collection data providers other than LinkedIn? Can LinkedIn share or has any open source projects that demonstrate an app with complex data model?

    opened by cliren 1
  • One-to-many relationship: retrieve child object from cache

    One-to-many relationship: retrieve child object from cache

    First of all, thanks for the library.

    I have two models, both conform to Model protocol:

    public struct Person {
        public let id: String
        public let name: String
    }
    
    public struct Group {
        public let id: String
        public let persons: [Person]
    }
    

    I'm putting a group into the cache:

    let person1 = Person(id: "1", name: "jj")
    let person2 = Person(id: "2", name: "name")
    let group = Group(id: "1", persons: [person1, person2])
    let groupDataProvider = ModelDataProvider<Group>()
    groupDataProvider.setData(group)
    

    and then trying to take a person out of there:

    let dataProvider = ModelDataProvider<Person>()
    dataProvider.fetchDataFromCache(withCacheKey: person1.modelIdentifier) { (model, error) in
        if let error = error {
            print("error \(error)")
        } else {
            print("model \(model) \(type(of: model))")
        }
    }
    

    However, nil is returned. Looks like we're unable to get child objects out of cache?

    opened by agordeev 3
  • How to purge all items in the DataProvide and empty the cache in one shot?

    How to purge all items in the DataProvide and empty the cache in one shot?

    When a user logs out, we need to purge but it doesn't seem that you guys support a complete purge...

    Is this the only way?

    // Purge let count = self?.usersDataProvider.count ?? 0 for index in stride(from: count, to: 0, by: -1) { self?.usersDataProvider.remove(at: index) }

    opened by rahimizad 1
  • CollectionDataProvider.fetchDataFromCache can fail to set the cacheKey

    CollectionDataProvider.fetchDataFromCache can fail to set the cacheKey

    When calling CollectionDataProvider.fetchDataFromCache, If there are no objects in the cache matching the cache key, nil is returned for the object array (I might prefer an empty array), but more importantly, the cache key is not set on the provider, so even though you have a delegate listening to the data provider, it will not get notified of subsequent additions to the collection. Here's the sequence I'm doing:

    collectionDataProvider = CollectionDataProvider<StoreItemPendingPurchase>()
    collectionDataProvider.delegate = self
    collectionDataProvider.fetchDataFromCache(withCacheKey: cacheKey)
    

    This returns nil for the error and nil for the object array. And the data provider's cacheKey is still nil. If somewhere else in the app someone sets data on the same cacheKey, I don't find out about it because my data provider's cacheKey is still nil.

    Is this expected? If there some way to set the cacheKey independently of using setData() or fetchDataFromCache()?

    opened by markkrenek 7
Releases(6.0.0)
  • 6.0.0(May 17, 2018)

    Full Swift 4.1 Upgrade

    This removes all Swift 4.1 warnings and updates the project to use the new Consistency Manager which has also been updated.

    This is backwards incompatible only because you need to upgrade to Swift 4.1 to use this version. There are no public API changes.

    Source code(tar.gz)
    Source code(zip)
  • 4.0.1(Oct 28, 2016)

    Making the ChangeTime object thread safe (#46)

    This affected the DataModelManager which should be thread safe. Mostly, things should not be affected, but it was throwing assertions if you access updateModel or updateModels from a different thread.

    Source code(tar.gz)
    Source code(zip)
  • 4.0.0(Oct 24, 2016)

    A minor change to the CacheDelegate protocol which helps make the DataModelManager API more flexible.

    To upgrade you should replace these methods in your CacheDelegate.

    Previous:

    func setModel<T: SimpleModel>(_ model: T, forKey cacheKey: String, context: Any?)
    func setCollection<T: SimpleModel>(_ collection: [T], forKey cacheKey: String, context: Any?)
    

    Now:

    func setModel(_ model: SimpleModel, forKey cacheKey: String, context: Any?)
    func setCollection(_ collection: [SimpleModel], forKey cacheKey: String, context: Any?)
    

    As far as we can tell, there isn't any need for the generic parameter here. If you have any problems, please create an issue.

    Source code(tar.gz)
    Source code(zip)
  • 3.0.0(Oct 3, 2016)

    Migrates the code to a better Swift 3 API. Version 2.0.0 also works on Swift 3, but there were no API changes (making migrations easier).

    See #39 for an overview of the API changes.

    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 22, 2016)

    Swift 3 release. This updates all the code to compile on Swift 3. It attempts a minimal API change to make it easier to migrate to. We will release a new version soon with a Swift 3 style API.

    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Sep 22, 2016)

    Swift 2.3 release for Carthage. There are no changes in this release for Cocoapods users, so we will not do a Cocoapods release for this version.

    Source code(tar.gz)
    Source code(zip)
  • 1.1.1(Sep 2, 2016)

  • 1.1.0(Aug 17, 2016)

    This updates the Consistency Manager to version 2.0.0. The main difference here is adding support for projections.

    See https://linkedin.github.io/RocketData/pages/095_projections.html and https://linkedin.github.io/ConsistencyManager-iOS/pages/055_projections.html.

    All current setups should continue to work normally.

    Source code(tar.gz)
    Source code(zip)
  • 1.0.1(Aug 9, 2016)

    The only functional change here is a bug fix. We also added travis and updated some documentation.

    Fixes

    • Bug fix where arrays were sometimes not updated #15
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Jul 27, 2016)

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
Melodic Caching for Swift

Johnny is a generic caching library written for Swift 4. Features Johnny can cache any model object that conforms to the Cachable protocol. Out-of-the

Zoltán Matók 37 Nov 21, 2022
Swift caching library

Cache A generic caching library for Swift. Cache depends on Foundation. This is still very much a work in progress. Usage Cache provides a simple Cach

Sam Soffes 210 Sep 9, 2022
A library and tool for interacting with both the local and remote asset caches.

Asset Cache Tool A library and tool for interacting with both the local and remote asset caches. This is based on research I did a few years ago on th

Kenneth Endfinger 20 Dec 23, 2022
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
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
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
Track is a thread safe cache write by Swift. Composed of DiskCache and MemoryCache which support LRU.

Track is a thread safe cache write by Swift. Composed of DiskCache and MemoryCache which support LRU. Features Thread safe: Implement by dispatch_sema

Cheer 268 Nov 21, 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
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
🏈 Cache CocoaPods for faster rebuild and indexing Xcode project.

Motivation Working on a project with a huge amount of pods I had some troubles: - Slow and unnecessary indexing of pods targets, which implementation

Vyacheslav Khorkov 487 Jan 5, 2023
A repository for showcasing my knowledge of the Objective-C++ programming language, and continuing to learn the language.

Learning Objective-C-Plus-Plus I hardly know anything about the Objective-C++ programming language. This document will go over all of my knowledge of

Sean P. Myrick V19.1.7.2 3 Nov 8, 2022
A repository for showcasing my knowledge of the Objective-C programming language, and continuing to learn the language.

Learning Objective-C I hardly know anything about the Objective-C programming language. This document will go over all of my knowledge of the Objectiv

Sean P. Myrick V19.1.7.2 3 Nov 8, 2022
Rock - Paper - Scissors game. CPU gives you a sign and asks to win or lose your move. Than you have to decide witch sign do you choose to score a point

RockPaperScissors 2nd challange from HackingWithSwift.com. The CPU gives you a sign (rock, paper or scissors) and asks you either to win or to lose th

Pavel Surový 0 Nov 27, 2021
Collect payments with iPhone, Apple Watch, and Siri using Apple Pay

Offering Apple Pay in Your App Collect payments with iPhone, Apple Watch, and Si

Edgar Papyan 4 Dec 14, 2021
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
Periodum-apple - iPad and macOS client for periodum.com

Periodum  iPad and macOS client for periodum.com

Umur Gedik 1 Jan 31, 2022
A comprehensive SDK for scanning Digimarc digital watermarks and the most common retail 1D barcodes & QR codes.

##Digimarc Mobile SDK for Apple Platforms The Digimarc Mobile SDK (DM SDK) is a comprehensive and robust scanning software for Digimarc Barcode (Produ

Digimarc 5 Jun 1, 2022
Find and save your favorite places!

Reqs Recommendation app to search for, organize, and save the places you love. TODOs: Implement UserDefaults for settings Complete annotation screen w

Joseph Gilmore 3 Nov 7, 2022