Commit 0b1f2688 by Demid Merzlyakov

DelayedStorage to optimize data saving

parent b24d371c
......@@ -209,6 +209,7 @@
CEDE4E8925EEFFEF007457E9 /* WdtDayNight.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEDE4E8825EEFFEF007457E9 /* WdtDayNight.swift */; };
CEDE4F0B25EFA3A7007457E9 /* UpdatableModelObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEDE4F0A25EFA3A7007457E9 /* UpdatableModelObject.swift */; };
CEDE4F0F25EFA3B4007457E9 /* UpdatableModelObjectInTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEDE4F0E25EFA3B4007457E9 /* UpdatableModelObjectInTime.swift */; };
CEE0A179262FA9650044C257 /* DelayedSaveStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEE0A178262FA9650044C257 /* DelayedSaveStorage.swift */; };
CEF959652600C2F900975FAA /* AnalyticsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF959642600C2F900975FAA /* AnalyticsService.swift */; };
CEF959692600C30500975FAA /* Global.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF959682600C30500975FAA /* Global.swift */; };
CEF9596C2600C32E00975FAA /* AnalyticsEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = CEF9596B2600C32E00975FAA /* AnalyticsEvent.swift */; };
......@@ -443,6 +444,7 @@
CEDE4E8825EEFFEF007457E9 /* WdtDayNight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WdtDayNight.swift; sourceTree = "<group>"; };
CEDE4F0A25EFA3A7007457E9 /* UpdatableModelObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatableModelObject.swift; sourceTree = "<group>"; };
CEDE4F0E25EFA3B4007457E9 /* UpdatableModelObjectInTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdatableModelObjectInTime.swift; sourceTree = "<group>"; };
CEE0A178262FA9650044C257 /* DelayedSaveStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelayedSaveStorage.swift; sourceTree = "<group>"; };
CEF959642600C2F900975FAA /* AnalyticsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsService.swift; sourceTree = "<group>"; };
CEF959682600C30500975FAA /* Global.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Global.swift; sourceTree = "<group>"; };
CEF9596B2600C32E00975FAA /* AnalyticsEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnalyticsEvent.swift; sourceTree = "<group>"; };
......@@ -1236,6 +1238,7 @@
children = (
CEFB857126174F7A00C5CDD2 /* Storage.swift */,
CEFB8577261750DF00C5CDD2 /* CoreData */,
CEE0A178262FA9650044C257 /* DelayedSaveStorage.swift */,
);
path = Storage;
sourceTree = "<group>";
......@@ -1593,6 +1596,7 @@
CD593BD32608BC3F00C93428 /* ForecastDayCell.swift in Sources */,
CD4742D0261200500061AC95 /* TodayAlertCell.swift in Sources */,
CD15DB4225DA806C00024727 /* TodayForecastTimePeriodCell.swift in Sources */,
CEE0A179262FA9650044C257 /* DelayedSaveStorage.swift in Sources */,
CE0456242629C04C003D252B /* NWSAlertsManager.swift in Sources */,
CE8962AB26175DF500CA274A /* CorePollutant.swift in Sources */,
CEC5276025E92DDA00DA58A5 /* WdtHourlySummary.swift in Sources */,
......
......@@ -150,7 +150,12 @@ public class LocationManager {
}
}
public static let shared = LocationManager(weatherUpdateSource: WdtWeatherSource(), healthSource: BlendHealthSource(), nwsAlertsManager: NWSAlertsManager(), storage: CoreDataStorage())
public static let shared = LocationManager(
weatherUpdateSource: WdtWeatherSource(),
healthSource: BlendHealthSource(),
nwsAlertsManager: NWSAlertsManager(),
storage: DelayedSaveStorage(storage: CoreDataStorage(), delay: 2))
public let maxLocationsCount = 12
public init(weatherUpdateSource: WeatherSource, healthSource: HealthSource, nwsAlertsManager: NWSAlertsManager, storage: Storage) {
......
......@@ -74,6 +74,7 @@ public struct Location {
guard self == other else { return false }
guard self.lastWeatherUpdateDate == other.lastWeatherUpdateDate else { return false }
guard self.health?.lastUpdateTime == other.health?.lastUpdateTime else { return false }
guard self.notifications?.updatedAt == other.notifications?.updatedAt else { return false }
return true
}
}
......
......@@ -103,10 +103,8 @@ public class CoreDataStorage: Storage {
}
private func save(context: NSManagedObjectContext) throws {
log.info("Context save: start")
if context.hasChanges {
try context.save()
log.info("Context save: success")
}
else {
log.info("Context save: no need")
......
//
// DelayedSaveStorage.swift
// 1Weather
//
// Created by Demid Merzlyakov on 21.04.2021.
//
import Foundation
/// A decorator Storage that adds delay before saving to the nested storage.
public class DelayedSaveStorage: Storage {
private let delay: TimeInterval
private let storage: Storage
private let savingQueue: OperationQueue = {
let queue = OperationQueue()
queue.name = "DelayedSaveStorageSavingQueue"
queue.maxConcurrentOperationCount = 1
return queue
}()
/// A "cache" to allow for loading after saving without waiting.
private var latestKnownAppData: AppData?
private let latestKnownAppDataSynchronizationQueue: OperationQueue = {
let queue = OperationQueue()
queue.name = "DelayedSaveStorageVariableAccessQueue"
queue.maxConcurrentOperationCount = 1
return queue
}()
public init(storage: Storage, delay: TimeInterval) {
self.delay = delay
self.storage = storage
}
public func save(locations: [Location], selectedIndex: Int?) {
latestKnownAppDataSynchronizationQueue.addOperation {
self.latestKnownAppData = AppData(selectedIndex: selectedIndex, locations: locations)
}
savingQueue.cancelAllOperations()
let saveOperation = BlockOperation()
saveOperation.addExecutionBlock { [weak saveOperation, weak self] in
guard saveOperation?.isCancelled == false else {
return
}
if let delay = self?.delay, delay > 0 {
Thread.sleep(forTimeInterval: delay)
}
guard saveOperation?.isCancelled == false else {
return
}
self?.storage.save(locations: locations, selectedIndex: selectedIndex)
}
savingQueue.addOperation(saveOperation)
}
public func load(completion: @escaping StorageCompletion) {
latestKnownAppDataSynchronizationQueue.addOperation { [weak self] in
if let lastKnownData = self?.latestKnownAppData {
completion(lastKnownData.locations, lastKnownData.selectedIndex, nil)
return
}
else {
self?.storage.load(completion: completion)
}
}
}
}
......@@ -7,6 +7,7 @@
import Foundation
/// locations list, selectedIndex, error
public typealias StorageCompletion = ([Location]?, Int?, Error?) -> ()
public protocol Storage {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment