Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve performance when has data conflicts #84

Merged
merged 2 commits into from Sep 20, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion RocketData/BatchDataProviderListener.swift
Expand Up @@ -30,7 +30,7 @@ open class BatchDataProviderListener: BatchListenerDelegate {
open weak var delegate: BatchDataProviderListenerDelegate?

/// The consistency manager which is backed by this instance
open let consistencyManager: ConsistencyManager
public let consistencyManager: ConsistencyManager

/// This is the batch listener from the consistency manager which contains most of the logic for doing batch listening
private let batchListener: BatchListener
Expand Down
41 changes: 29 additions & 12 deletions RocketData/CollectionDataProvider.swift
Expand Up @@ -43,7 +43,7 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
}

/// The DataModelManager which backs this data provider.
open let dataModelManager: DataModelManager
public let dataModelManager: DataModelManager

/// This saves the batchListener instance. It is public because it implements the BatchListenable protocol. You should never edit this directly.
open weak var batchListener: BatchDataProviderListener?
Expand Down Expand Up @@ -129,7 +129,10 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
anything else you want.
*/
open func setData(_ data: [T], cacheKey: String?, shouldCache: Bool = true, context: Any? = nil) {
self.dataHolder.setData(data, changeTime: ChangeTime())
let isSuccess = self.dataHolder.setData(data, changeTime: ChangeTime())
if !isSuccess {
return
}
self.cacheKey = cacheKey
if shouldCache, let cacheKey = cacheKey {
dataModelManager.cacheCollection(data, forKey: cacheKey, context: context)
Expand Down Expand Up @@ -193,7 +196,12 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B

if cacheKey != self.cacheKey && cacheDataFresh {
if let collection = collection {
self.dataHolder.setData(collection, changeTime: ChangeTime())
let isSuccess = self.dataHolder.setData(collection, changeTime: ChangeTime())
// If the method such as setData is not called from the main thread, there may still be conflicts. If so, just return
if !isSuccess {
return
}

self.listenForUpdates()
self.cacheKey = cacheKey
}
Expand All @@ -220,8 +228,11 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
if newData.count > 0 {
var updatedData = data
updatedData.insert(contentsOf: newData, at: index)
dataHolder.setData(updatedData, changeTime: ChangeTime())

let isSuccess = dataHolder.setData(updatedData, changeTime: ChangeTime())
if !isSuccess {
return
}

if shouldCache, let cacheKey = cacheKey {
dataModelManager.cacheCollection(data, forKey: cacheKey, context: context)
}
Expand Down Expand Up @@ -267,7 +278,10 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
open func update(_ element: T, at index: Int, shouldCache: Bool = true, context: Any? = nil) {
var updatedData = data
updatedData[index] = element
dataHolder.setData(updatedData, changeTime: ChangeTime())
let isSuccess = dataHolder.setData(updatedData, changeTime: ChangeTime())
if !isSuccess {
return
}

if shouldCache, let cacheKey = cacheKey {
self.dataModelManager.cacheCollection(data, forKey: cacheKey, context: context)
Expand Down Expand Up @@ -298,7 +312,10 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
open func remove(at index: Int, shouldCache: Bool = true, context: Any? = nil) {
var updatedData = data
updatedData.remove(at: index)
dataHolder.setData(updatedData, changeTime: ChangeTime())
let isSuccess = dataHolder.setData(updatedData, changeTime: ChangeTime())
if !isSuccess {
return
}

if shouldCache, let cacheKey = cacheKey {
dataModelManager.cacheCollection(data, forKey: cacheKey, context: context)
Expand Down Expand Up @@ -327,7 +344,7 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
- parameter dataModelManager: The data model manager to associate with this change.
- parameter context: This context will be passed onto the cache delegate. Default nil.
*/
open static func setData(_ data: [T], cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil) {
public static func setData(_ data: [T], cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil) {
let collectionDataProvider = CollectionDataProvider<T>(dataModelManager: dataModelManager)
collectionDataProvider.setData(data, cacheKey: cacheKey, context: context)
}
Expand All @@ -347,7 +364,7 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
- parameter completion: This completion block is called when the insert has succeeded (but the data may not yet be propegated to the cache).
If there is no data in the cache for this cacheKey, it will return an error as the insert has failed. Default nil.
*/
open static func insert(_ newData: [T], at index: @escaping (([T])->Int), cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
public static func insert(_ newData: [T], at index: @escaping (([T])->Int), cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
let collectionDataProvider = CollectionDataProvider<T>(dataModelManager: dataModelManager)
collectionDataProvider.fetchDataFromCache(withCacheKey: cacheKey) { cachedData, error in
if let cachedData = cachedData {
Expand All @@ -370,7 +387,7 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
- parameter completion: This completion block is called when the insert has succeeded (but the data may not yet be propegated to the cache).
If there is no data in the cache for this cacheKey, it will return an error as the insert has failed. Default nil.
*/
open static func append(_ newData: [T], cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
public static func append(_ newData: [T], cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
let collectionDataProvider = CollectionDataProvider<T>(dataModelManager: dataModelManager)
collectionDataProvider.fetchDataFromCache(withCacheKey: cacheKey) { cachedData, error in
collectionDataProvider.append(newData, context: context)
Expand All @@ -393,7 +410,7 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
- parameter completion: This completion block is called when the insert has succeeded (but the data may not yet be propegated to the cache).
If there is no data in the cache for this cacheKey, it will return an error as the insert has failed. Default nil.
*/
open static func update(_ element: T, at index: @escaping (([T])->Int), cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
public static func update(_ element: T, at index: @escaping (([T])->Int), cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
let collectionDataProvider = CollectionDataProvider<T>(dataModelManager: dataModelManager)
collectionDataProvider.fetchDataFromCache(withCacheKey: cacheKey) { cachedData, error in
if let cachedData = cachedData {
Expand All @@ -417,7 +434,7 @@ open class CollectionDataProvider<T: SimpleModel>: ConsistencyManagerListener, B
- parameter completion: This completion block is called when the insert has succeeded (but the data may not yet be propegated to the cache).
If there is no data in the cache for this cacheKey, it will return an error as the insert has failed. Default nil.
*/
open static func removeAtIndex(_ index: @escaping (([T])->Int), cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
public static func removeAtIndex(_ index: @escaping (([T])->Int), cacheKey: String, dataModelManager: DataModelManager, context: Any? = nil, completion: ((NSError?)->())? = nil) {
let collectionDataProvider = CollectionDataProvider<T>(dataModelManager: dataModelManager)
collectionDataProvider.fetchDataFromCache(withCacheKey: cacheKey) { cachedData, error in
if let cachedData = cachedData {
Expand Down
6 changes: 4 additions & 2 deletions RocketData/DataHolder.swift
Expand Up @@ -34,12 +34,14 @@ struct DataHolder<T> {
This modifies the data in the data holder.
- parameter data: The new data.
- parameter changeTime: The new change time to set on lastUpdated.
- Returns: whether to successfully set the data
*/
mutating func setData(_ data: T, changeTime: ChangeTime) {
@discardableResult mutating func setData(_ data: T, changeTime: ChangeTime) -> Bool {
if lastUpdated.after(changeTime) {
return
return false
}
self.data = data
lastUpdated = changeTime
return true
}
}
4 changes: 2 additions & 2 deletions RocketData/DataModelManager.swift
Expand Up @@ -30,10 +30,10 @@ import ConsistencyManager
open class DataModelManager {

/// Cache Delegate. This is strongly retained since it is required by the library.
open let cacheDelegate: CacheDelegate
public let cacheDelegate: CacheDelegate

/// Consistency Manager.
open let consistencyManager = ConsistencyManager()
public let consistencyManager = ConsistencyManager()

let sharedCollectionManager = SharedCollectionManager()

Expand Down
14 changes: 11 additions & 3 deletions RocketData/DataProvider.swift
Expand Up @@ -28,7 +28,7 @@ open class DataProvider<T: SimpleModel>: ConsistencyManagerListener, BatchListen
open weak var delegate: DataProviderDelegate?

/// The data model manager which is backing this DataProvider
open let dataModelManager: DataModelManager
public let dataModelManager: DataModelManager

/**
You can set this variable to pause and unpause listening for changes to data.
Expand Down Expand Up @@ -129,7 +129,11 @@ open class DataProvider<T: SimpleModel>: ConsistencyManagerListener, BatchListen
or anything else you want.
*/
open func setData(_ data: T?, updateCache: Bool = true, context: Any? = nil) {
self.dataHolder.setData(data, changeTime: ChangeTime())
let isSuccess = self.dataHolder.setData(data, changeTime: ChangeTime())
if !isSuccess {
return
}

if let data = data {
if let cacheKey = data.modelIdentifier , updateCache {
dataModelManager.cacheModel(data, forKey: cacheKey, context: context)
Expand Down Expand Up @@ -171,7 +175,11 @@ open class DataProvider<T: SimpleModel>: ConsistencyManagerListener, BatchListen

if cacheDataFresh {
if let model = model {
self.dataHolder.setData(model, changeTime: ChangeTime())
let isSuccess = self.dataHolder.setData(model, changeTime: ChangeTime())
if !isSuccess {
return
}

self.listenForUpdates()
}
completion(model, error)
Expand Down
2 changes: 1 addition & 1 deletion RocketData/Logger.swift
Expand Up @@ -16,7 +16,7 @@ import Foundation
open class Log {

/// Singleton accessor
open static let sharedInstance = Log()
public static let sharedInstance = Log()

/// Delegate for the class. If nil, then it will do default logging. Otherwise, it will leave it up to the delegate.
open weak var delegate: LogDelegate?
Expand Down
8 changes: 4 additions & 4 deletions SampleApp/Podfile.lock
@@ -1,15 +1,15 @@
PODS:
- ConsistencyManager (6.0.0)
- PINCache (2.3)
- RocketData (6.0.0):
- RocketData (6.0.1):
- ConsistencyManager (~> 6.0.0)

DEPENDENCIES:
- PINCache
- RocketData (from `..`)

SPEC REPOS:
https://github.com/CocoaPods/Specs.git:
https://github.com/cocoapods/specs.git:
- ConsistencyManager
- PINCache

Expand All @@ -20,8 +20,8 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
ConsistencyManager: 10d92488107167a8d9df3cd93e529a15282ceaec
PINCache: ce36ed282031b92fc7733ffe831f474ff80fddc2
RocketData: 407c9aeff026cf9281683717d78d26e15f6f8a98
RocketData: 2663345b70a12a0dcfb0752fb438c799866d450f

PODFILE CHECKSUM: cb6653d292a93b194174111d0be6bb93b45e1b23

COCOAPODS: 1.5.0
COCOAPODS: 1.5.3
4 changes: 2 additions & 2 deletions SampleApp/Pods/Local Podspecs/RocketData.podspec.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions SampleApp/Pods/Manifest.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion SampleApp/Pods/Target Support Files/RocketData/Info.plist

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.