Digital PCT265 story MVAPCT-48 - Initial demo of loading feed from cache
This commit is contained in:
parent
c636cc1ca4
commit
8c32dbbd7d
@ -96,6 +96,7 @@
|
|||||||
AF43A7411FC5FA6F008E9347 /* MVMCoreViewProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
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, ); }; };
|
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 */; };
|
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 */; };
|
AF60A7F2289212CA00919EEB /* MVMError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F1289212CA00919EEB /* MVMError.swift */; };
|
||||||
AF60A7F4289212EB00919EEB /* MVMCoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F3289212EB00919EEB /* MVMCoreError.swift */; };
|
AF60A7F4289212EB00919EEB /* MVMCoreError.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF60A7F3289212EB00919EEB /* MVMCoreError.swift */; };
|
||||||
AF686FDA2A8A876A008F666A /* NavigationOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF686FD92A8A876A008F666A /* NavigationOperation.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 = "<group>"; };
|
AF43A7401FC5FA6F008E9347 /* MVMCoreViewProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreViewProtocol.h; sourceTree = "<group>"; };
|
||||||
AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionObject.h; sourceTree = "<group>"; };
|
AF43A74A1FC6109F008E9347 /* MVMCoreSessionObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreSessionObject.h; sourceTree = "<group>"; };
|
||||||
AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreSessionObject.m; sourceTree = "<group>"; };
|
AF43A74B1FC6109F008E9347 /* MVMCoreSessionObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreSessionObject.m; sourceTree = "<group>"; };
|
||||||
|
AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreCache+Extension.swift"; sourceTree = "<group>"; };
|
||||||
AF60A7F1289212CA00919EEB /* MVMError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMError.swift; sourceTree = "<group>"; };
|
AF60A7F1289212CA00919EEB /* MVMError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMError.swift; sourceTree = "<group>"; };
|
||||||
AF60A7F3289212EB00919EEB /* MVMCoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreError.swift; sourceTree = "<group>"; };
|
AF60A7F3289212EB00919EEB /* MVMCoreError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreError.swift; sourceTree = "<group>"; };
|
||||||
AF686FD92A8A876A008F666A /* NavigationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationOperation.swift; sourceTree = "<group>"; };
|
AF686FD92A8A876A008F666A /* NavigationOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationOperation.swift; sourceTree = "<group>"; };
|
||||||
@ -656,6 +658,7 @@
|
|||||||
children = (
|
children = (
|
||||||
AF43A7091FC4F415008E9347 /* MVMCoreCache.h */,
|
AF43A7091FC4F415008E9347 /* MVMCoreCache.h */,
|
||||||
AF43A7081FC4F415008E9347 /* MVMCoreCache.m */,
|
AF43A7081FC4F415008E9347 /* MVMCoreCache.m */,
|
||||||
|
AF4955E12BAB1EB200567276 /* MVMCoreCache+Extension.swift */,
|
||||||
605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */,
|
605A9A292ABD712F00487E47 /* MVMCoreLoggingHandler.swift */,
|
||||||
6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */,
|
6042E8FB2B3094680031644B /* MVMCoreLoggingHandlerHelper.h */,
|
||||||
D288D5F426C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift */,
|
D288D5F426C6EFE000A5C365 /* MVMCoreLoggingHandler+Extension.swift */,
|
||||||
@ -902,6 +905,7 @@
|
|||||||
AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */,
|
AFBB96351FBA34310008D868 /* MVMCoreErrorConstants.m in Sources */,
|
||||||
AF43A5881FBB67D6008E9347 /* MVMCoreActionUtility.m in Sources */,
|
AF43A5881FBB67D6008E9347 /* MVMCoreActionUtility.m in Sources */,
|
||||||
AFED77A61FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m in Sources */,
|
AFED77A61FCCA29400BAE689 /* MVMCoreViewControllerStoryBoardMappingObject.m in Sources */,
|
||||||
|
AF4955E22BAB1EB200567276 /* MVMCoreCache+Extension.swift in Sources */,
|
||||||
016CF36925FA6DD400B82A1F /* ClientParameterHandler.swift in Sources */,
|
016CF36925FA6DD400B82A1F /* ClientParameterHandler.swift in Sources */,
|
||||||
5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */,
|
5846ABF42B44BB9000FA6C76 /* Collection+Safe.swift in Sources */,
|
||||||
AF69D4F7286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift in Sources */,
|
AF69D4F7286EA0B800BC6862 /* ActionPreviousSubmitHandler.swift in Sources */,
|
||||||
|
|||||||
@ -383,8 +383,14 @@
|
|||||||
if (requestParameters.backgroundRequest) {
|
if (requestParameters.backgroundRequest) {
|
||||||
return [self loadBackgroundRequest:requestParameters dataForPage:dataForPage delegateObject:delegateObject];
|
return [self loadBackgroundRequest:requestParameters dataForPage:dataForPage delegateObject:delegateObject];
|
||||||
} else {
|
} else {
|
||||||
|
if (!requestParameters.noloadingOverlay) {
|
||||||
|
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] startLoading];
|
||||||
|
}
|
||||||
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:NO];
|
MVMCoreLoadRequestOperation *loadOperation = [[MVMCoreLoadRequestOperation alloc] initWithRequestParameters:requestParameters dataForPage:dataForPage delegateObject:delegateObject backgroundLoad:NO];
|
||||||
loadOperation.identifier = requestParameters.identifier;
|
loadOperation.identifier = requestParameters.identifier;
|
||||||
|
[loadOperation setCompletionBlock:^{
|
||||||
|
[[MVMCoreLoadingOverlayHandler sharedLoadingOverlay] stopLoading:YES];
|
||||||
|
}];
|
||||||
[self.blockingLoadQueue addOperation:loadOperation];
|
[self.blockingLoadQueue addOperation:loadOperation];
|
||||||
return loadOperation;
|
return loadOperation;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,6 +38,38 @@ public enum PopBackError: MVMError, CustomStringConvertible {
|
|||||||
|
|
||||||
@objc
|
@objc
|
||||||
public extension MVMCoreLoadRequestOperation {
|
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
|
@objc
|
||||||
func popBackToPage(for loadObject: MVMCoreLoadObject) {
|
func popBackToPage(for loadObject: MVMCoreLoadObject) {
|
||||||
Task(priority: .high) {
|
Task(priority: .high) {
|
||||||
|
|||||||
@ -90,6 +90,8 @@
|
|||||||
*/
|
*/
|
||||||
+ (void)removeCaches:(nullable NSDictionary *)cacheDictionary;
|
+ (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.
|
/** Creates the view controller based on the load object passed in.
|
||||||
* @param loadObject The load data from the cache or server.
|
* @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.*/
|
* @param completionHandler The completion handler to load once finished. Returns any loaded view controller and the load.*/
|
||||||
|
|||||||
@ -132,71 +132,74 @@
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
// No provided load object, check the cache for data first..
|
// 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]) {
|
[MVMCoreLoadRequestOperation checkCacheForDataForRequest:self.requestParameters completionHandler:^(NSDictionary *pageFromCache, NSDictionary *modulesFromCache) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log if loaded from cache.
|
if ([self checkAndHandleForCancellation]) {
|
||||||
if (pageFromCache) {
|
return;
|
||||||
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.
|
// Log if loaded from cache.
|
||||||
[MVMCoreLoadRequestOperation sendRequest:requestForMissingData loadObject:loadObject completionHandler:^(NSDictionary * _Nullable json) {
|
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 ENABLE_HARD_CODED_RESPONSE
|
||||||
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(modifyJSON:)]) {
|
if ([[MVMCoreObject sharedInstance].globalLoadDelegate respondsToSelector:@selector(modifyJSON:)]) {
|
||||||
json = [[MVMCoreObject sharedInstance].globalLoadDelegate modifyJSON:json];
|
json = [[MVMCoreObject sharedInstance].globalLoadDelegate modifyJSON:json];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
NSString *serverProcessTime = [(NSDictionary *)json objectChainOfKeysOrIndexes:@[@"ResponseInfo", @"timeStamp"]] ?: @"0";
|
NSString *serverProcessTime = [(NSDictionary *)json objectChainOfKeysOrIndexes:@[@"ResponseInfo", @"timeStamp"]] ?: @"0";
|
||||||
|
|
||||||
if(!self.backgroundLoad && loadObject.requestParameters.pageType && serverProcessTime) {
|
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];
|
[[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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
if ([loadObject.operation checkAndHandleForCancellation]) {
|
||||||
[MVMCoreLoadRequestOperation handleLoadObject:loadObject error:error];
|
return;
|
||||||
} else {
|
}
|
||||||
// Something to show, or nothing was expected to show, can finish.
|
|
||||||
[MVMCoreLoadRequestOperation loadFinished:loadObject loadedViewController:nil errorObject:error];
|
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) {
|
if (!error.nativeDrivenErrorScreen) {
|
||||||
|
|
||||||
// Server driven screen, create normally
|
// 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 {
|
} else {
|
||||||
// Get the proper native error screen from the delegate
|
// Get the proper native error screen from the delegate
|
||||||
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
[MVMCoreDispatchUtility performBlockOnMainThread:^{
|
||||||
|
|||||||
101
MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift
Normal file
101
MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift
Normal file
@ -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<NSString, CachedData>()
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,6 +36,8 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO
|
|||||||
// Checks the set of modules to be cached for the given module
|
// Checks the set of modules to be cached for the given module
|
||||||
- (BOOL)shouldCacheJSONWithModule:(nonnull NSString *)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
|
// For pages external to the mobile first framework to be added to the list to not cache
|
||||||
- (void)addPageTypesToNotCache:(nullable NSArray <NSString *>*)array;
|
- (void)addPageTypesToNotCache:(nullable NSArray <NSString *>*)array;
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,8 @@
|
|||||||
|
|
||||||
@property (nullable, strong, nonatomic) NSCache *playerItemCache;
|
@property (nullable, strong, nonatomic) NSCache *playerItemCache;
|
||||||
|
|
||||||
|
@property (nullable, strong, nonatomic) NSSet *itemsToPersist;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation MVMCoreCache
|
@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.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.playerItemCache = [[NSCache alloc] init];
|
||||||
|
|
||||||
|
self.itemsToPersist = [NSSet setWithObjects:@"myFeed",@"FeedOrder",@"HabContent",@"launchModule",@"tabBar",@"DeepLinkService", nil];
|
||||||
}
|
}
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
@ -140,6 +144,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
|
|||||||
|
|
||||||
// First checks the cache by page type.
|
// First checks the cache by page type.
|
||||||
dictionary = [weakSelf.pageTypeCache objectForKey:pageType];
|
dictionary = [weakSelf.pageTypeCache objectForKey:pageType];
|
||||||
|
if (!dictionary) {
|
||||||
|
NSError *error = nil;
|
||||||
|
dictionary = [[DataCacheManager shared] loadForKey:pageType error:&error];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// If no pagetype, return whole cache
|
// If no pagetype, return whole cache
|
||||||
@ -176,6 +184,12 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt";
|
|||||||
NSDictionary *moduleDictionary = [weakSelf.moduleCache objectForKey:module];
|
NSDictionary *moduleDictionary = [weakSelf.moduleCache objectForKey:module];
|
||||||
if (moduleDictionary) {
|
if (moduleDictionary) {
|
||||||
[modulesDictionary setObject:moduleDictionary forKey:module];
|
[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];
|
[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
|
#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 {
|
- (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"];
|
NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"];
|
||||||
if (shouldCache == nil || shouldCache.boolValue) {
|
if (shouldCache == nil || shouldCache.boolValue) {
|
||||||
[weakSelf.pageTypeCache setObject:jsonDictionary forKey:pageType];
|
[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"];
|
NSNumber *shouldCache = [jsonDictionary optionalNumberForKey:@"cache"];
|
||||||
if (shouldCache == nil || shouldCache.boolValue) {
|
if (shouldCache == nil || shouldCache.boolValue) {
|
||||||
[weakSelf.moduleCache setObject:obj forKey:key];
|
[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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user