From 4bdd93dbe57a18eee70843d4c51c329e94060a7c Mon Sep 17 00:00:00 2001 From: Scott Pfeil Date: Wed, 27 Mar 2024 13:38:13 -0400 Subject: [PATCH] Digital PCT265 story MVAPCT-48 - Minor cache code cleanup --- .../MVMCoreCache+Extension.swift | 100 ++++++++---------- MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h | 7 +- MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m | 43 ++++---- 3 files changed, 73 insertions(+), 77 deletions(-) diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift index 8658be3..ac5b0fb 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache+Extension.swift @@ -46,60 +46,51 @@ public class CachedData: Codable { } } -@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! }() +@objc public class PersistentCacheManager: NSObject { + @objc public static let shared = PersistentCacheManager() + private let fileManager = FileManager.default + private lazy var documentsDirectory = { fileManager.urls(for: .documentDirectory, in: .userDomainMask).first! }() - public override init() {} + private 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 save(data: [String: AnyHashable], forKey key: String, expirationDate: Date) throws { + let cachedData = CachedData(data: data, expirationDate: expirationDate) + 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 + let keyNSString = NSString(string: key) + 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 { + return decodedCachedData.data + } else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "CACHEDFEED: EXPIRED, key:\(key)") + throw CacheError.dataExpired + } + } catch { + // Remove item from the cache on any failure. + try fileManager.removeItem(at: filePath) + + switch error { + case is DecodingError: + throw CacheError.deserializationFailed + default: + throw CacheError.loadFailed(error) + } } - } catch { - // Remove item from the cache on any failure. - try fileManager.removeItem(at: filePath) - - switch error { - case is DecodingError: - throw CacheError.deserializationFailed - default: - throw CacheError.loadFailed(error) - } - } -// } - } + } + @objc public func remove(forKey key: String) throws { let filePath = self.filePath(forKey: key) try fileManager.removeItem(at: filePath) @@ -109,12 +100,13 @@ public class CachedData: Codable { let fileURLs = try fileManager.contentsOfDirectory(at: documentsDirectory, includingPropertiesForKeys: nil, options: .skipsHiddenFiles) - for fileURL in fileURLs where fileURL.pathExtension == "json" { - try FileManager.default.removeItem(at: fileURL) - } + + for fileURL in fileURLs where fileURL.pathExtension == "json" { + try FileManager.default.removeItem(at: fileURL) + } } - private func filePath(forKey key: String) -> URL { - return documentsDirectory.appendingPathComponent("\(key).json") - } + 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 945e22a..07ec07c 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.h @@ -40,7 +40,7 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO - (BOOL)isJSONExpired:(nonnull NSDictionary *)jsonDictionary; /// Returns the expiry time for the object. -- (NSTimeInterval)getExpiryForJSON:(nonnull NSDictionary *)jsonDictionary; +- (nonnull NSDate *)getExpirationDateForJSON:(nonnull NSDictionary *)jsonDictionary; /// Checks if the page is to be persistently cached. - (BOOL)shouldPersistentlyCachePage:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType; @@ -94,7 +94,10 @@ typedef void(^MVMCoreGetImageBlock)(UIImage * _Nullable, NSData * _Nullable, BOO - (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary; /// Adds the json to the persistent cache by pageType. -- (void)addPageToPersistentCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType expiry:(NSTimeInterval)expiry; +- (void)addPageToPersistentCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType expirationDate:(nonnull NSDate *)expirationDate; + +/// Adds the json to the persistent cache by module. +- (void)addModuleToPersistentCache:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName expirationDate:(nonnull NSDate *)expirationDate; #pragma mark - Advanced Insertion diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m index a1223aa..754f4a3 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m @@ -104,17 +104,18 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; } - (BOOL)isJSONExpired:(nonnull NSDictionary *)jsonDictionary { - NSTimeInterval expiryTime = [self getExpiryForJSON:jsonDictionary]; - NSTimeInterval timeSinceUnixEpoc = [[NSDate date] timeIntervalSince1970]; - if (timeSinceUnixEpoc > expiryTime) { - [MVMCoreLoggingHandler logDebugMessageWithDelegate:[NSString stringWithFormat:@"CACHEDFEED: EXPIRED %@ %@ %f %f",[jsonDictionary stringForKey:KeyPageType],[jsonDictionary stringForKey:@"moduleName"],timeSinceUnixEpoc,expiryTime]]; + NSDate *expirationDate = [self getExpirationDateForJSON:jsonDictionary]; + NSDate *today = [NSDate date]; + if (today > expirationDate) { + [MVMCoreLoggingHandler logDebugMessageWithDelegate:[NSString stringWithFormat:@"CACHEDFEED: NEW DATA ALREADY EXPIRED %@ %@ %@ %@",[jsonDictionary stringForKey:KeyPageType],[jsonDictionary stringForKey:@"moduleName"],today,expirationDate]]; } - return timeSinceUnixEpoc > expiryTime; + return today > expirationDate; } -- (NSTimeInterval)getExpiryForJSON:(nonnull NSDictionary *)jsonDictionary { +- (nonnull NSDate *)getExpirationDateForJSON:(nonnull NSDictionary *)jsonDictionary { NSDictionary *cachePolicy = [jsonDictionary dict:@"cachePolicy"]; - return [[cachePolicy dict:@"expiry"] doubleValue] * 1000.0; + NSTimeInterval interval = [[cachePolicy string:@"expiry"] doubleValue] / 1000; + return [NSDate dateWithTimeIntervalSince1970:interval]; } - (BOOL)shouldPersistentlyCacheJSON:(nonnull NSDictionary *)jsonDictionary { @@ -161,12 +162,12 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; - (NSDictionary * _Nullable)fetchPageFromPersistentCache:(nonnull NSString *)pageType { NSError *error = nil; - return [[DataCacheManager shared] loadForKey:pageType error:&error]; + return [[PersistentCacheManager shared] loadForKey:pageType error:&error]; } - (NSDictionary * _Nullable)fetchModuleFromPersistentCache:(nonnull NSString *)moduleName { NSError *error = nil; - return [[DataCacheManager shared] loadForKey:moduleName error:&error]; + return [[PersistentCacheManager shared] loadForKey:moduleName error:&error]; } #pragma mark - Advanced Fetch @@ -258,14 +259,14 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; [self addModulesToCache:jsonDictionary queue:nil waitUntilFinished:NO completionBlock:NULL]; } -- (void)addPageToPersistentCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType expiry:(NSTimeInterval)expiry { +- (void)addPageToPersistentCache:(nonnull NSDictionary *)jsonDictionary pageType:(nonnull NSString *)pageType expirationDate:(nonnull NSDate *)expirationDate { NSError *error = nil; - [[DataCacheManager shared] saveWithData:jsonDictionary forKey:pageType cacheDuration:expiry shouldPersist:YES error:&error]; + [[PersistentCacheManager shared] saveWithData:jsonDictionary forKey:pageType expirationDate:expirationDate error:&error]; } -- (void)addModuleToPersistentCache:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName expiry:(NSTimeInterval)expiry { +- (void)addModuleToPersistentCache:(nonnull NSDictionary *)jsonDictionary moduleName:(nonnull NSString *)moduleName expirationDate:(nonnull NSDate *)expirationDate { NSError *error = nil; - [[DataCacheManager shared] saveWithData:jsonDictionary forKey:moduleName cacheDuration:expiry shouldPersist:YES error:&error]; + [[PersistentCacheManager shared] saveWithData:jsonDictionary forKey:moduleName expirationDate:expirationDate error:&error]; } #pragma mark - Advanced Insertion @@ -297,10 +298,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; [weakSelf.pageTypeCache setObject:jsonDictionary forKey:pageType]; if (![self shouldPersistentlyCachePage:jsonDictionary pageType:pageType]) { - [[DataCacheManager shared] removeForKey:pageType error:nil]; + [[PersistentCacheManager shared] removeForKey:pageType error:nil]; return; } - [self addPageToPersistentCache:jsonDictionary pageType:pageType expiry:[self getExpiryForJSON:jsonDictionary]]; + [self addPageToPersistentCache:jsonDictionary pageType:pageType expirationDate:[self getExpirationDateForJSON:jsonDictionary]]; } } if (completionBlock) { @@ -333,10 +334,10 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; [weakSelf.moduleCache setObject:jsonDictionary forKey:module]; if (![self shouldPersistentlyCacheModule:jsonDictionary module:module]) { - [[DataCacheManager shared] removeForKey:module error:nil]; + [[PersistentCacheManager shared] removeForKey:module error:nil]; return; } - [self addModuleToPersistentCache:jsonDictionary moduleName:module expiry:[self getExpiryForJSON:jsonDictionary]]; + [self addModuleToPersistentCache:jsonDictionary moduleName:module expirationDate:[self getExpirationDateForJSON:jsonDictionary]]; } if (completionBlock) { [(queue ?: weakSelf.completionQueue) addOperations:@[[NSBlockOperation blockOperationWithBlock:completionBlock]] waitUntilFinished:waitUntilFinished]; @@ -372,7 +373,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; } - (void)clearPersistentJSONCache { - [[DataCacheManager shared] removeAllAndReturnError:nil]; + [[PersistentCacheManager shared] removeAllAndReturnError:nil]; } - (void)clearMFCache { @@ -412,7 +413,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; } }]; [self.pageTypeQueue addOperations:@[removeOperation] waitUntilFinished:waitUntilFinished]; - [[DataCacheManager shared] removeForKey:pageType error:nil]; + [[PersistentCacheManager shared] removeForKey:pageType error:nil]; } - (void)removeJSONForModule:(nonnull NSString *)module queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock { @@ -436,7 +437,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; } }]; [self.moduleQueue addOperations:@[removeOperation] waitUntilFinished:waitUntilFinished]; - [[DataCacheManager shared] removeForKey:module error:nil]; + [[PersistentCacheManager shared] removeForKey:module error:nil]; } - (void)removeJSONForModules:(nonnull NSArray *)modules queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock { @@ -456,7 +457,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; // Removes json from cache with module key. [weakSelf.moduleCache removeObjectForKey:obj]; } - [[DataCacheManager shared] removeForKey:obj error:nil]; + [[PersistentCacheManager shared] removeForKey:obj error:nil]; } }]; if (completionBlock) {