From 7451c2a5c0e973affc6afff0996a99fbc29e244e Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 2 Mar 2020 14:54:48 -0500 Subject: [PATCH 1/3] change the base decode functions --- .../ActionType/ActionModelProtocol.swift | 4 - .../MVMCore/Models/Model/ModelRegistry.swift | 135 ++++++++++-------- 2 files changed, 72 insertions(+), 67 deletions(-) diff --git a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift index 27b62c2..66f8586 100644 --- a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift +++ b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift @@ -8,10 +8,6 @@ import Foundation -public enum ActionCodingKey: String, CodingKey { - case actionType -} - public protocol ActionModelProtocol: ModelProtocol { var actionType: String? { get set } diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index 057f9c1..54e1d89 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -9,7 +9,6 @@ import Foundation - public struct ModelRegistry { public enum Error: Swift.Error { @@ -45,24 +44,32 @@ public struct ModelRegistry { } private static func getCategory(for type: T.Type) -> Category? { - return categories["\(T.self)"] + // Temporary code till we find a better solution. + //create a string representation of the Type + let description = String(describing: T.self) + + //split the protocol composition (if there is one) + let protocols = description.components(separatedBy: "&").compactMap{$0.trimmingCharacters(in: .whitespaces)} + + //if this is a protocol composotion, loop through each protocol + //for a category lookup + if protocols.count > 1 { + return protocols.compactMap({ (p) -> Category? in + guard let c = categories[p] else { + return nil + } + return c + }).first + }//otherwise use the description of the type for the lookup + else { + return categories[description] + } } public static func getType(for name: String, with type: T.Type) -> ModelProtocol.Type? { return getCategory(for: type)?.instanceTypes[name] } - private static func getCategory(for typeString: String) -> Category? { - for (_, value) in categories where value.codingKey == typeString { - return value - } - return nil - } - - public static func getType(for name: String, with typeString: String) -> ModelProtocol.Type? { - return getCategory(for: typeString)?.instanceTypes[name] - } - public static func getCodingKey(for type: T.Type) throws -> AnyCodingKey { guard let category = getCategory(for: type) else { throw ModelRegistry.Error.decoderOther(message: "decodeModelsIfPresent only works for objects implementing the ModelProtocol protocol") @@ -77,32 +84,46 @@ extension KeyedDecodingContainer where Key: CodingKey { // MARK: - Decode /// Decodes to a registered model based on the identifier - public func decodeModel(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> M { - - guard let model: ModelProtocol = try decodeModelIfPresent(codingKey: codingKey, typeCodingKey: typeCodingKey) else { + public func decodeModel(codingKey: KeyedDecodingContainer.Key) throws -> T { + guard let model: T = try decodeModelIfPresent(codingKey: codingKey) else { MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") throw ModelRegistry.Error.decoderErrorObjectNotPresent } - - if let model = model as? M { - return model - } else { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderError: \(codingKey)") - throw ModelRegistry.Error.decoderError + return model + } + + /// Decodes an array of registered model based on the identifiers. + public func decodeModels(codingKey: KeyedDecodingContainer.Key) throws -> [T] { + guard let model: [T] = try decodeModelsIfPresent(codingKey: codingKey) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") + throw ModelRegistry.Error.decoderErrorObjectNotPresent } + return model + } + + /// Decodes an array with arrays of models based on the identifiers. + public func decodeModels2D(codingKey: KeyedDecodingContainer.Key) throws -> [[T]] { + guard let models: [[T]] = try decodeModels2DIfPresent(codingKey: codingKey) else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") + throw ModelRegistry.Error.decoderErrorObjectNotPresent + } + return models } // MARK: - DecodeIfPresent /// Decodes to a registered model based on the identifier, optional. - public func decodeModelIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> M? { - //get the identifier string - guard contains(codingKey), - let container = try? nestedContainer(keyedBy: TypeKey.self, forKey: codingKey), - let identifier = try? container.decodeIfPresent(String.self, forKey: typeCodingKey) - else { return nil } + public func decodeModelIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> T? { + //create coding key + let typeCodingKey = try ModelRegistry.getCodingKey(for: T.self) - guard let type = ModelRegistry.getType(for: identifier, with: typeCodingKey.stringValue) else { + //get the container that holds the identifier value + guard contains(codingKey), + let container = try? self.nestedContainer(keyedBy: AnyCodingKey.self, forKey: codingKey), + let identifier = try container.decodeIfPresent(String.self, forKey: typeCodingKey) else { return nil } + + //get the type from the identifier value in the Registry + guard let type = ModelRegistry.getType(for: identifier, with: T.self) else { MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelProtocol not mapped: \(identifier)") throw ModelRegistry.Error.decoderErrorModelNotMapped } @@ -110,7 +131,7 @@ extension KeyedDecodingContainer where Key: CodingKey { //decode the type using the decoder let model = try type.decode(keyedContainer: self, codingKey: codingKey) - if let model = model as? M { + if let model = model as? T { return model } else { MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderError: \(codingKey)") @@ -119,39 +140,21 @@ extension KeyedDecodingContainer where Key: CodingKey { } /// Decodes an array of registered model based on the identifiers, optional. - public func decodeModelsIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [ModelProtocol]? { + public func decodeModelsIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> [T]? { guard contains(codingKey), var container = try? self.nestedUnkeyedContainer(forKey: codingKey) else { return nil } - return try container.decodeModelsIfPresent(typeCodingKey: typeCodingKey) - } - - /// Decodes an array of registered model based on the identifiers. - public func decodeModels(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [ModelProtocol] { - guard let models: [ModelProtocol] = try decodeModelsIfPresent(codingKey: codingKey, typeCodingKey: typeCodingKey) else { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") - throw ModelRegistry.Error.decoderErrorObjectNotPresent - } - return models + return try container.decodeModelsIfPresent() } /// Decodes an array with arrays of models based on the identifiers, optional. - public func decodeModels2DIfPresent(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [[ModelProtocol]]? { + public func decodeModels2DIfPresent(codingKey: KeyedDecodingContainer.Key) throws -> [[T]]? { guard contains(codingKey), var container = try? nestedUnkeyedContainer(forKey: codingKey) else { return nil } - return try container.decodeModels2DIfPresent(typeCodingKey: typeCodingKey) - } - - /// Decodes an array with arrays of models based on the identifiers. - public func decodeModels2D(codingKey: KeyedDecodingContainer.Key, typeCodingKey: TypeKey) throws -> [[ModelProtocol]] { - guard let models: [[ModelProtocol]] = try decodeModels2DIfPresent(codingKey: codingKey, typeCodingKey: typeCodingKey) else { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorObjectNotPresent: \(codingKey)") - throw ModelRegistry.Error.decoderErrorObjectNotPresent - } - return models + return try container.decodeModels2DIfPresent() } } @@ -205,36 +208,42 @@ public extension KeyedEncodingContainer where Key: CodingKey { public extension UnkeyedDecodingContainer { /// Decodes the container into a list of Models. - mutating func decodeModelsIfPresent(typeCodingKey: TypeKey) throws -> [ModelProtocol]? { - - var models = [ModelProtocol]() + mutating func decodeModelsIfPresent() throws -> [T]? { + let typeCodingKey = try ModelRegistry.getCodingKey(for: T.self) + var models = [T]() var containerCopy = self + // Iterate and decode each. while !containerCopy.isAtEnd { - let nestedContainer = try containerCopy.nestedContainer(keyedBy: TypeKey.self) + let nestedContainer = try containerCopy.nestedContainer(keyedBy: AnyCodingKey.self) if let identifier = try nestedContainer.decodeIfPresent(String.self, forKey: typeCodingKey) { - guard let type = ModelRegistry.getType(for: identifier, with: typeCodingKey.stringValue) else { + guard let type = ModelRegistry.getType(for: identifier, with: T.self) else { MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorModelNotMapped: \(identifier)") throw ModelRegistry.Error.decoderErrorModelNotMapped } // Now get the decoder to use for the type let decoder = try self.superDecoder() - let model = try type.init(from: decoder) - models.append(model) + if let model = try type.init(from: decoder) as? T { + models.append(model) + } else { + MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderError: \(typeCodingKey)") + throw ModelRegistry.Error.decoderError + } } } return models } /// Convenience function for decoding the container into a list of lists of Models. - mutating func decodeModels2DIfPresent(typeCodingKey: TypeKey) throws -> [[ModelProtocol]]? { - - var modelLists = [[ModelProtocol]]() + mutating func decodeModels2DIfPresent() throws -> [[T]]? { + let typeCodingKey = try ModelRegistry.getCodingKey(for: T.self) + var modelLists = [[T]]() var containerCopy = self + // Iterate and decode each. while !containerCopy.isAtEnd { var arraycontainerCopy = try containerCopy.nestedUnkeyedContainer() - guard let models = try arraycontainerCopy.decodeModelsIfPresent(typeCodingKey: typeCodingKey) else { + guard let models: [T] = try arraycontainerCopy.decodeModelsIfPresent() else { MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ModelRegistry Error decoderErrorModelNotMapped: \(typeCodingKey)") throw ModelRegistry.Error.decoderErrorModelNotMapped } From d243b9623c420395feb7521889fa663ebff226c4 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 2 Mar 2020 15:21:01 -0500 Subject: [PATCH 2/3] condense --- .../MVMCore/Models/Model/ModelRegistry.swift | 27 ++++++------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index 54e1d89..b002175 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -45,25 +45,14 @@ public struct ModelRegistry { private static func getCategory(for type: T.Type) -> Category? { // Temporary code till we find a better solution. - //create a string representation of the Type - let description = String(describing: T.self) - - //split the protocol composition (if there is one) - let protocols = description.components(separatedBy: "&").compactMap{$0.trimmingCharacters(in: .whitespaces)} - - //if this is a protocol composotion, loop through each protocol - //for a category lookup - if protocols.count > 1 { - return protocols.compactMap({ (p) -> Category? in - guard let c = categories[p] else { - return nil - } - return c - }).first - }//otherwise use the description of the type for the lookup - else { - return categories[description] - } + //if this is a protocol composotion, loop through each protocol for a category lookup + let protocols = String(describing: T.self).components(separatedBy: "&").compactMap{$0.trimmingCharacters(in: .whitespaces)} + return protocols.compactMap({ (p) -> Category? in + guard let c = categories[p] else { + return nil + } + return c + }).first } public static func getType(for name: String, with type: T.Type) -> ModelProtocol.Type? { From 78654b689d33e101031349e7f4fa0935160686d8 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 3 Mar 2020 15:08:24 -0500 Subject: [PATCH 3/3] Cleaning --- MVMCore/MVMCore/Constants/MVMCoreConstants.h | 1 + MVMCore/MVMCore/Constants/MVMCoreConstants.m | 1 + .../MVMCoreDismissViewControllerOperation.m | 5 +++++ .../PresentationHandling/MVMCoreNavigationOperation.m | 4 ++++ .../MVMCorePresentViewControllerOperation.m | 5 +++++ 5 files changed, 16 insertions(+) diff --git a/MVMCore/MVMCore/Constants/MVMCoreConstants.h b/MVMCore/MVMCore/Constants/MVMCoreConstants.h index e4ac6be..e653ffe 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreConstants.h +++ b/MVMCore/MVMCore/Constants/MVMCoreConstants.h @@ -42,6 +42,7 @@ extern NSString * const URLComponentKeepAlive; extern NSString * const NotificationResponseLoaded; extern NSString * const MVMCoreNotificationGoingToServer; +extern NSString * const MVMCoreNotificationViewControllerChanged; #pragma mark - Image Cache extern NSTimeInterval const ImageTimeOut; diff --git a/MVMCore/MVMCore/Constants/MVMCoreConstants.m b/MVMCore/MVMCore/Constants/MVMCoreConstants.m index cf0761f..887ee0c 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreConstants.m +++ b/MVMCore/MVMCore/Constants/MVMCoreConstants.m @@ -29,6 +29,7 @@ NSString * const URLComponentKeepAlive = @"isAlive.jsp"; NSString * const NotificationResponseLoaded = @"responseLoaded"; NSString * const MVMCoreNotificationGoingToServer = @"MVMCoreGoServer"; +NSString * const MVMCoreNotificationViewControllerChanged = @"MVMCoreNotificationViewControllerChanged"; #pragma mark - Image Cache NSTimeInterval const ImageTimeOut = 60; diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCoreDismissViewControllerOperation.m b/MVMCore/MVMCore/PresentationHandling/MVMCoreDismissViewControllerOperation.m index bd2287d..4a09cb4 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCoreDismissViewControllerOperation.m +++ b/MVMCore/MVMCore/PresentationHandling/MVMCoreDismissViewControllerOperation.m @@ -7,6 +7,7 @@ // #import "MVMCoreDismissViewControllerOperation.h" +#import "MVMCoreConstants.h" typedef NS_ENUM(NSInteger, DismissType) { DismissTypeTop = 0, @@ -77,6 +78,10 @@ typedef NS_ENUM(NSInteger, DismissType) { if (viewController.presentedViewController || viewController.presentingViewController) { [viewController dismissViewControllerAnimated:self.animate completion:^{ [self markAsFinished]; + // Notify that page has changed + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:MVMCoreNotificationViewControllerChanged object:nil]; + }); }]; } else { [self markAsFinished]; diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m index ee960aa..5a39b73 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m +++ b/MVMCore/MVMCore/PresentationHandling/MVMCoreNavigationOperation.m @@ -242,6 +242,10 @@ [self.delegate navigationController:navigationController displayedViewController:viewController]; } [self markAsFinished]; + // Notify that page has changed + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:MVMCoreNotificationViewControllerChanged object:nil]; + }); } - (nullable id )navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { diff --git a/MVMCore/MVMCore/PresentationHandling/MVMCorePresentViewControllerOperation.m b/MVMCore/MVMCore/PresentationHandling/MVMCorePresentViewControllerOperation.m index 809f0cc..6b7c51b 100644 --- a/MVMCore/MVMCore/PresentationHandling/MVMCorePresentViewControllerOperation.m +++ b/MVMCore/MVMCore/PresentationHandling/MVMCorePresentViewControllerOperation.m @@ -10,6 +10,7 @@ #import "MVMCoreAlertController.h" #import "MVMCorePresentAnimationOperation.h" #import "MVMCoreDispatchUtility.h" +#import "MVMCoreConstants.h" @interface MVMCorePresentViewControllerOperation () @@ -74,6 +75,10 @@ static void * XXContext = &XXContext; animationOperation.delegate = self.delegate; [animationOperation setCompletionBlock:^{ [self markAsFinished]; + // Notify that page has changed + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [[NSNotificationCenter defaultCenter] postNotificationName:MVMCoreNotificationViewControllerChanged object:nil]; + }); }]; [[NSOperationQueue mainQueue] addOperation:animationOperation]; }