From 8c32dbbd7d3616a75ec9bf6cf08e3776b7a549b6 Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Wed, 20 Mar 2024 19:09:13 -0400 Subject: [PATCH] Digital PCT265 story MVAPCT-48 - Initial demo of loading feed from cache --- MVMCore/MVMCore.xcodeproj/project.pbxproj | 4 + .../MVMCore/LoadHandling/MVMCoreLoadHandler.m | 6 + ...VMCoreLoadRequestOperation+Extension.swift | 32 +++++ .../MVMCoreLoadRequestOperation.h | 2 + .../MVMCoreLoadRequestOperation.m | 122 ++++++++++-------- .../MVMCoreCache+Extension.swift | 101 +++++++++++++++ MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h | 2 + MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m | 30 +++++ 8 files changed, 242 insertions(+), 57 deletions(-) create mode 100644 MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift diff --git a/MVMCore/MVMCore.xcodeproj/project.pbxproj b/MVMCore/MVMCore.xcodeproj/project.pbxproj index da71c4e..c827f0f 100644 --- a/MVMCore/MVMCore.xcodeproj/project.pbxproj +++ b/MVMCore/MVMCore.xcodeproj/project.pbxproj @@ -96,6 +96,7 @@ AF43A7411FC5FA6F008E9347 /* MVMCoreViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF43A74C1FC6109F008E9347 /* MVMCoreSessionObject.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; AF43A74D1FC6109F008E9347 /* MVMCoreSessionObject.m in Sources */ = {isa = PBXBuildFile; fileRef = AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */; }; + AF4955E22BAB1EB200567276 /* MVMCoreCache+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */; }; AF60A7F2289212CA00919EEB /* MVMError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F1289212CA00919EEB /* MVMError.swift */; }; AF60A7F4289212EB00919EEB /* MVMCoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F3289212EB00919EEB /* MVMCoreError.swift */; }; AF686FDA2A8A876A008F666A /* NavigationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FD92A8A876A008F666A /* NavigationOperation.swift */; }; @@ -252,6 +253,7 @@ AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewProtocol.h; sourceTree = ""; }; AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionObject.h; sourceTree = ""; }; AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreSessionObject.m; sourceTree = ""; }; + AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreCache+Extension.swift"; sourceTree = ""; }; AF60A7F1289212CA00919EEB /* MVMError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMError.swift; sourceTree = ""; }; AF60A7F3289212EB00919EEB /* MVMCoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreError.swift; sourceTree = ""; }; AF686FD92A8A876A008F666A /* NavigationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationOperation.swift; sourceTree = ""; }; @@ -656,6 +658,7 @@ children = ( AF43A7091FC4F415008E9347 /* MVMCoreCache.h */, AF43A7081FC4F415008E9347 /* MVMCoreCache.m */, + AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */, 605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */, 6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */, D288D5F426C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift */, @@ -902,6 +905,7 @@ AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */, AF43A5881FBB67D6008E9347 /* MVMCoreActionUtility.m in Sources */, AFED77A61FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m in Sources */, + AF4955E22BAB1EB200567276 /* MVMCoreCache+Extension.swift in Sources */, 016CF36925FA6DD400B82A1F /* ClientParameterHandler.swift in Sources */, 5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */, AF69D4F7286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift in Sources */, diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m index 4e39318..af912a4 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m @@ -383,8 +383,14 @@ if (requestParameters.backgroundRequest) { return [self loadBackgroundRequest:requestParameters dataForPage:dataForPage delegateObject:delegateObject]; } else { + if (!requestParameters.noloadingOverlay) { + [[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading]; + } MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:NO]; loadOperation.identifier = requestParameters.identifier; + [loadOperation setCompletionBlock:^{ + [[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:YES]; + }]; [self.blockingLoadQueue addOperation:loadOperation]; return loadOperation; } diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation+Extension.swift b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation+Extension.swift index 181dae8..d3b4ea1 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation+Extension.swift +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation+Extension.swift @@ -38,6 +38,38 @@ public enum PopBackError: MVMError, CustomStringConvertible { @objc public extension MVMCoreLoadRequestOperation { + + @objc + @MainActor + func checkIfNewControllerIsNeeded(loadObject: MVMCoreLoadObject) -> Bool { + guard loadObject.requestParameters?.replaceViewIfOnStackElseLoadWithStyle == true, + let pageType = loadObject.pageType else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: Controller shouldn't be replaced.") + return true + } + let newVC = MVMCoreViewControllerMappingObject.shared()?.createMFViewController(ofTemplate: loadObject.pageJSON?.optionalStringForKey("template"), pageType: pageType) + guard let index = NavigationHandler.shared().navigationController?.viewControllers.firstIndex(where: { controller in + (controller as? MVMCoreViewControllerProtocol)?.pageType == pageType && type(of: controller) == type(of: newVC) + }) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: No matching controller found.") + return true + } + if index == NavigationHandler.shared().navigationController!.viewControllers.count - 1 { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: Controller is already showing.") + Task { + MVMCoreLoadRequestOperation.loadFinished(loadObject, loadedViewController: nil, errorObject: nil) + } + } else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: Pop back to controller.") + guard let operation = try? NavigationHandler.shared().getOperationPopToViewController(with: pageType, navigationController: loadObject.requestParameters?.navigationController, delegateObject: loadObject.delegateObject, animated: !(loadObject.requestParameters?.shouldNotAnimatePush ?? false)) else { return true } + Task { + await navigate(with: operation, loadObject: loadObject) + MVMCoreLoadRequestOperation.loadFinished(loadObject, loadedViewController: nil, errorObject: nil) + } + } + return false + } + @objc func popBackToPage(for loadObject: MVMCoreLoadObject) { Task(priority: .high) { diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h index fa034e9..fe334b3 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.h @@ -90,6 +90,8 @@ */ + (void)removeCaches:(nullable NSDictionary *)cacheDictionary; ++ (void)notifyListenersOfNewResponse:(nullable NSDictionary *)pages modules:(nullable NSDictionary *)modules systemParameters:(nullable NSDictionary *)systemParameters loadObject:(nonnull MVMCoreLoadObject *)loadObject; + /** Creates the view controller based on the load object passed in. * @param loadObject The load data from the cache or server. * @param completionHandler The completion handler to load once finished. Returns any loaded view controller and the load.*/ diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m index 4563544..3517361 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m @@ -132,71 +132,74 @@ } else { // No provided load object, check the cache for data first.. - [MVMCoreLoadRequestOperation checkCacheForDataForRequest:self.requestParameters completionHandler:^(NSDictionary *pageFromCache, NSDictionary *modulesFromCache) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ - if ([self checkAndHandleForCancellation]) { - return; - } - - // Log if loaded from cache. - if (pageFromCache) { - MVMCoreLog(@"loaded from cache page %@",[MVMCoreActionUtility formatDictionaryAsJSONString:pageFromCache]); - } - if (modulesFromCache) { - MVMCoreLog(@"loaded from cache modules %@",[MVMCoreActionUtility formatDictionaryAsJSONString:modulesFromCache]); - } - - // Create a load object from any data we fetched. - MVMCoreLoadObject *loadObject = [self createLoadObjectWithPageFromCache:pageFromCache modulesFromCache:modulesFromCache]; - - // Check if we need to go to server for missing data. - MVMCoreRequestParameters *requestForMissingData = [MVMCoreLoadRequestOperation createRequestForDataWithLoadObject:loadObject]; - if (!requestForMissingData) { + [MVMCoreLoadRequestOperation checkCacheForDataForRequest:self.requestParameters completionHandler:^(NSDictionary *pageFromCache, NSDictionary *modulesFromCache) { - [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:@"0" requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache]; - - // We have all the needed data, continue with the load. - [MVMCoreLoadRequestOperation handleLoadObject:loadObject error:nil]; - } else { - - if(!self.backgroundLoad && loadObject.requestParameters.pageType) { - [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadStartedFor:loadObject.requestParameters.pageType requestUUID:loadObject.identifier requestURL:loadObject.requestParameters.URL.absoluteString]; + if ([self checkAndHandleForCancellation]) { + return; } - - // Send a new request to the server. - [MVMCoreLoadRequestOperation sendRequest:requestForMissingData loadObject:loadObject completionHandler:^(NSDictionary * _Nullable json) { - + + // Log if loaded from cache. + if (pageFromCache) { + MVMCoreLog(@"loaded from cache page %@",[MVMCoreActionUtility formatDictionaryAsJSONString:pageFromCache]); + } + if (modulesFromCache) { + MVMCoreLog(@"loaded from cache modules %@",[MVMCoreActionUtility formatDictionaryAsJSONString:modulesFromCache]); + } + + // Create a load object from any data we fetched. + MVMCoreLoadObject *loadObject = [self createLoadObjectWithPageFromCache:pageFromCache modulesFromCache:modulesFromCache]; + + // Check if we need to go to server for missing data. + MVMCoreRequestParameters *requestForMissingData = [MVMCoreLoadRequestOperation createRequestForDataWithLoadObject:loadObject]; + if (!requestForMissingData) { + + [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:@"0" requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache]; + + // We have all the needed data, continue with the load. + [MVMCoreLoadRequestOperation handleLoadObject:loadObject error:nil]; + } else { + + if(!self.backgroundLoad && loadObject.requestParameters.pageType) { + [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadStartedFor:loadObject.requestParameters.pageType requestUUID:loadObject.identifier requestURL:loadObject.requestParameters.URL.absoluteString]; + } + + // Send a new request to the server. + [MVMCoreLoadRequestOperation sendRequest:requestForMissingData loadObject:loadObject completionHandler:^(NSDictionary * _Nullable json) { + #if ENABLE_HARD_CODED_RESPONSE - if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(modifyJSON:)]) { - json = [[MVMCoreObject sharedInstance].globalLoadDelegate modifyJSON:json]; - } + if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(modifyJSON:)]) { + json = [[MVMCoreObject sharedInstance].globalLoadDelegate modifyJSON:json]; + } #endif - - NSString *serverProcessTime = [(NSDictionary *)json objectChainOfKeysOrIndexes:@[@"ResponseInfo", @"timeStamp"]] ?: @"0"; - - if(!self.backgroundLoad && loadObject.requestParameters.pageType && serverProcessTime) { - [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:serverProcessTime requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache]; - } - - // Process the data retrieved from the server. - [MVMCoreLoadRequestOperation processJSONFromServer:json loadObject:loadObject completionHandler:^(MVMCoreLoadObject * _Nonnull loadObject, MVMCoreErrorObject * _Nullable error) { - if ([loadObject.operation checkAndHandleForCancellation]) { - return; + NSString *serverProcessTime = [(NSDictionary *)json objectChainOfKeysOrIndexes:@[@"ResponseInfo", @"timeStamp"]] ?: @"0"; + + if(!self.backgroundLoad && loadObject.requestParameters.pageType && serverProcessTime) { + [[MVMCoreLoggingHandler sharedLoggingHandler] logPageLoadCompleteFor:loadObject.requestParameters.pageType serverProcessingTime:serverProcessTime requestURL:loadObject.requestParameters.URL.absoluteString requestUUID:loadObject.identifier isFromCache:loadObject.pageDataFromCache]; } - if (loadObject.pageDataFromCache || loadObject.pageType) { + // Process the data retrieved from the server. + [MVMCoreLoadRequestOperation processJSONFromServer:json loadObject:loadObject completionHandler:^(MVMCoreLoadObject * _Nonnull loadObject, MVMCoreErrorObject * _Nullable error) { - // Can continue loading with the page. - [MVMCoreLoadRequestOperation handleLoadObject:loadObject error:error]; - } else { - // Something to show, or nothing was expected to show, can finish. - [MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error]; - } + if ([loadObject.operation checkAndHandleForCancellation]) { + return; + } + + if (loadObject.pageDataFromCache || loadObject.pageType) { + + // Can continue loading with the page. + [MVMCoreLoadRequestOperation handleLoadObject:loadObject error:error]; + } else { + // Something to show, or nothing was expected to show, can finish. + [MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error]; + } + }]; }]; - }]; - } - }]; + } + }]; + }); } } @@ -581,9 +584,14 @@ }; if (!error.nativeDrivenErrorScreen) { - // Server driven screen, create normally - [MVMCoreLoadRequestOperation createViewControllerWithLoadObject:loadObject completionHandler:completionHandler]; + [MVMCoreDispatchUtility performBlockOnMainThread:^{ + if ([loadObject.operation checkIfNewControllerIsNeededWithLoadObject:loadObject]) { + [MVMCoreDispatchUtility performBlockInBackground:^{ + [MVMCoreLoadRequestOperation createViewControllerWithLoadObject:loadObject completionHandler:completionHandler]; + }]; + } + }]; } else { // Get the proper native error screen from the delegate [MVMCoreDispatchUtility performBlockOnMainThread:^{ diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift new file mode 100644 index 0000000..ac03a82 --- /dev/null +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift @@ -0,0 +1,101 @@ +// +// Cache.swift +// JSONCreator +// +// Created by Matt Bruce on 3/20/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// +import Foundation + +public enum CacheError: Error { + case serializationFailed + case deserializationFailed + case dataNotFound + case dataExpired + case saveFailed(Error) + case loadFailed(Error) +} + +public class CachedData: Codable { + public var data: [String: AnyHashable] + public var expirationDate: Date + enum CodingKeys: CodingKey { + case data, expirationDate + } + + public init(data: [String: AnyHashable], expirationDate: Date) { + self.data = data + self.expirationDate = expirationDate + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(expirationDate, forKey: .expirationDate) + let dataAsData = try JSONSerialization.data(withJSONObject: data, options: []) + try container.encode(dataAsData, forKey: .data) + } + + required public init(from decoder: Decoder) throws { + let values = try decoder.container(keyedBy: CodingKeys.self) + expirationDate = try values.decode(Date.self, forKey: .expirationDate) + let dataAsData = try values.decode(Data.self, forKey: .data) + guard let jsonData = try JSONSerialization.jsonObject(with: dataAsData, options: []) as? [String: AnyHashable] else { + throw CacheError.deserializationFailed + } + data = jsonData + } +} + +@objc public class DataCacheManager: NSObject { + @objc public static let shared = DataCacheManager() +// private let cache = NSCache() + private let fileManager = FileManager.default + private lazy var documentsDirectory = { fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! }() + + public override init() {} + + @objc public func save(data: [String: AnyHashable], forKey key: String, cacheDuration: TimeInterval, shouldPersist: Bool = true) throws { + let expirationDate = Date().addingTimeInterval(cacheDuration) + let cachedData = CachedData(data: data, expirationDate: expirationDate) +// cache.setObject(cachedData, forKey: NSString(string: key)) + if shouldPersist { + let filePath = self.filePath(forKey: key) + do { + let dataToSave = try JSONEncoder().encode(cachedData) + try dataToSave.write(to: filePath, options: .atomicWrite) + } catch let error as EncodingError { + throw CacheError.serializationFailed + } catch { + throw CacheError.saveFailed(error) + } + } + } + + @objc public func load(forKey key: String) throws -> [String: AnyHashable] { + let keyNSString = NSString(string: key) +// if let cachedObject = cache.object(forKey: keyNSString), +// Date() < cachedObject.expirationDate { +// return cachedObject.data +// } else { + let filePath = self.filePath(forKey: key) + do { + let data = try Data(contentsOf: filePath) + let decodedCachedData = try JSONDecoder().decode(CachedData.self, from: data) + if Date() < decodedCachedData.expirationDate { +// cache.setObject(decodedCachedData, forKey: keyNSString) + return decodedCachedData.data + } else { + throw CacheError.dataExpired + } + } catch let error as DecodingError { + throw CacheError.deserializationFailed + } catch { + throw CacheError.loadFailed(error) + } +// } + } + + private func filePath(forKey key: String) -> URL { + return documentsDirectory.appendingPathComponent("\(key).json") + } +} diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h index ca15d8d..66686b4 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h @@ -36,6 +36,8 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO // Checks the set of modules to be cached for the given module - (BOOL)shouldCacheJSONWithModule:(nonnull NSString *)module; +- (BOOL)shouldPersistentlyCache:(nonnull NSDictionary *)jsonDictionary identifier:(nonnull NSString *)identifier; + // For pages external to the mobile first framework to be added to the list to not cache - (void)addPageTypesToNotCache:(nullable NSArray *)array; diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m index 8c43b9e..aef62c8 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m @@ -39,6 +39,8 @@ @property (nullable, strong, nonatomic) NSCache *playerItemCache; +@property (nullable, strong, nonatomic) NSSet *itemsToPersist; + @end @implementation MVMCoreCache @@ -65,6 +67,8 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; self.videoQueue = dispatch_queue_create("video_queue", dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INTERACTIVE, 0)); self.playerItemCache = [[NSCache alloc] init]; + + self.itemsToPersist = [NSSet setWithObjects:@"myFeed",@"FeedOrder",@"HabContent",@"launchModule",@"tabBar",@"DeepLinkService", nil]; } return self; } @@ -140,6 +144,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; // First checks the cache by page type. dictionary = [weakSelf.pageTypeCache objectForKey:pageType]; + if (!dictionary) { + NSError *error = nil; + dictionary = [[DataCacheManager shared] loadForKey:pageType error:&error]; + } } else { // If no pagetype, return whole cache @@ -176,6 +184,12 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; NSDictionary *moduleDictionary = [weakSelf.moduleCache objectForKey:module]; if (moduleDictionary) { [modulesDictionary setObject:moduleDictionary forKey:module]; + } else { + NSError *error = nil; + moduleDictionary = [[DataCacheManager shared] loadForKey:module error:&error]; + if (moduleDictionary) { + [modulesDictionary setObject:moduleDictionary forKey:module]; + } } } @@ -206,6 +220,13 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; [self addModulesToCache:jsonDictionary queue:nil waitUntilFinished:NO completionBlock:NULL]; } +- (BOOL)shouldPersistentlyCache:(nonnull NSDictionary *)jsonDictionary identifier:(nonnull NSString *)identifier { + if ([self.itemsToPersist containsObject:identifier]) { + return YES; + } + return NO; +} + #pragma mark - Advanced Insertion - (void)addPageToCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock { @@ -230,6 +251,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"]; if (shouldCache == nil || shouldCache.boolValue) { [weakSelf.pageTypeCache setObject:jsonDictionary forKey:pageType]; + if ([self shouldPersistentlyCache:jsonDictionary identifier:pageType]) { + NSError *error = nil; + [[DataCacheManager shared] saveWithData:jsonDictionary forKey:pageType cacheDuration:604800 shouldPersist:YES error:&error]; + } } } } @@ -267,6 +292,11 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"]; if (shouldCache == nil || shouldCache.boolValue) { [weakSelf.moduleCache setObject:obj forKey:key]; + + if ([self shouldPersistentlyCache:obj identifier:key]) { + NSError *error = nil; + [[DataCacheManager shared] saveWithData:obj forKey:key cacheDuration:604800 shouldPersist:YES error:&error]; + } } } }];