added userInfo into the Decoders

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2022-05-10 12:05:57 -05:00
parent fa43578968
commit cb053464b5
3 changed files with 125 additions and 33 deletions

View File

@ -158,6 +158,7 @@
D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */; };
D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCBA23C65BC300C44CC4 /* Percent.swift */; };
D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */; };
EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */; };
EA3B264C25FC0B7600008074 /* ModelHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */; };
/* End PBXBuildFile section */
@ -307,6 +308,7 @@
D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInterval.swift; sourceTree = "<group>"; };
D2DEDCBA23C65BC300C44CC4 /* Percent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Percent.swift; sourceTree = "<group>"; };
D2E1FAD82260C3E400AEFD8C /* DelegateObject.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DelegateObject.swift; sourceTree = "<group>"; };
EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Decoder+UserInfo.swift"; sourceTree = "<group>"; };
EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHandlerProtocol.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -435,6 +437,7 @@
isa = PBXGroup;
children = (
946EE1AA237B5C940036751F /* Decoder.swift */,
EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */,
946EE1B3237B619D0036751F /* Encoder.swift */,
0A42538E23F3414800554656 /* Codable+Helpers.swift */,
);
@ -911,6 +914,7 @@
AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */,
AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */,
AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */,
EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */,
01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */,
D27073D125BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift in Sources */,
AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */,

View File

@ -0,0 +1,109 @@
//
// Decoder+UserInfo.swift
// MVMCore
//
// Created by Matt Bruce on 5/10/22.
// Copyright © 2022 myverizon. All rights reserved.
//
import Foundation
extension CodingUserInfoKey {
internal static let delegateObjectKey = CodingUserInfoKey(rawValue: "delegateObject")!
internal static let contextKey = CodingUserInfoKey(rawValue: "context")!
}
// MARK: - DelegateObject
public extension JSONDecoder {
/// Adds a delegate object to the decoder for use in the model initializers.
func add(value: Any, for key: CodingUserInfoKey) {
userInfo.updateValue(value, forKey: key)
}
}
public extension Decoder {
/// Gets a delegate object from the decoder for use in the model initializers. Had to be added before decode.
func get<T: DelegateObject>() throws -> T? {
return userInfo[.delegateObjectKey] as? T
}
}
// MARK: - DecodingContext
/// Class used to be added into the Decoder's userInfo object to store
/// key/value pairs to be used within the Decoding process.
public class DecodingContext {
/// Key/Value store
fileprivate var userInfo: [String: Any] = [:]
public init(){ }
/// Used to access value
/// - Parameter key: key for value
/// - Returns: value returns if the key exists
public func value(forKey key: String) -> Any? {
return userInfo[key]
}
}
extension Decoder {
///wrapping getter to call internal userInfo for this object
public var context: DecodingContext? {
userInfo[.contextKey] as? DecodingContext
}
/// Gets Typed value for key in the context
/// - Parameter key: Identifier
/// - Returns: Typed value
public func getContext<T>(key: String) throws -> T? {
context?.userInfo[key] as? T
}
/// Sets value for key in the context
/// - Parameters:
/// - value: Object
/// - key: Identifier
public func setContext(value: Any, for key: String) {
context?.userInfo[key] = value
}
/// Removes value for key in the context
/// - Parameter key: Identifier
public func removeContext(for key: String) {
context?.userInfo.removeValue(forKey: key)
}
/// This is a wrapping function that is meant to be used along with a "decode" method. It will save a key/value pair locally
/// and then this key/value pair is removed immediately after the completion handler is executed so that no other classes
/// will mistakenly use this value.
/// - Parameters:
/// - value: Object that you are wanting to save
/// - key: Identifier to get the Value
/// - completion: Code that will run after the value is set
public func setContext(value: Any, for key: String, completion: (() throws -> Void)) throws {
setContext(value: value, for: key)
try completion()
removeContext(for: key)
}
}
extension JSONDecoder {
/// Helper method to initialize a JSONDecoder
/// - Parameter delegateObject: Delegate Object
/// - Returns: JSONDecoder
public class func create(delegateObject: DelegateObject? = nil) throws -> JSONDecoder {
let decoder = JSONDecoder()
decoder.add(value: DecodingContext(), for: .contextKey)
if let delegateObject = delegateObject {
decoder.add(value: delegateObject, for: .delegateObjectKey)
}
return decoder
}
///wrapping getter to call internal userInfo for this object
public var context: DecodingContext? {
get { return userInfo[.contextKey] as? DecodingContext }
}
}

View File

@ -25,6 +25,16 @@ extension Data {
}
}
extension JSONDecoder {
/// Decodes a top-level value of the given type from the given JSON representation, and adds the delegate object if provided.
func decode<T>(_ type: T.Type, from data: Data, delegateObject: DelegateObject?) throws -> T where T : Decodable {
if let delegateObject = delegateObject {
add(value: delegateObject, for: .delegateObjectKey)
}
return try decode(T.self, from: data)
}
}
extension KeyedDecodingContainerProtocol {
public func decode<T: Decodable>(forKey key: Key) throws -> T {
return try decode(T.self, forKey: key)
@ -42,7 +52,8 @@ extension Decodable {
public static func decode(jsonDict: [String: Any], delegateObject: DelegateObject? = nil) throws -> Self {
let jsonData = try JSONSerialization.data(withJSONObject: jsonDict)
do {
return try jsonData.decode(delegateObject: delegateObject)
let decoder = try JSONDecoder.create(delegateObject: delegateObject)
return try jsonData.decode(using: decoder)
} catch {
throw JSONError.other(error: error)
}
@ -64,35 +75,3 @@ extension Decodable {
}
}
}
public enum DecoderKeyError: Error {
case createKey
}
public extension JSONDecoder {
/// Adds a delegate object to the decoder for use in the model initializers.
func add<T: DelegateObject>(delegateObject: T) throws {
guard let key = CodingUserInfoKey(rawValue: "delegateObject") else {
throw DecoderKeyError.createKey
}
userInfo.updateValue(delegateObject, forKey: key)
}
/// Decodes a top-level value of the given type from the given JSON representation, and adds the delegate object if provided.
func decode<T>(_ type: T.Type, from data: Data, delegateObject: DelegateObject?) throws -> T where T : Decodable {
if let delegateObject = delegateObject {
try add(delegateObject: delegateObject)
}
return try decode(T.self, from: data)
}
}
public extension Decoder {
/// Gets a delegate object from the decoder for use in the model initializers. Had to be added before decode.
func get<T: DelegateObject>() throws -> T? {
guard let key = CodingUserInfoKey(rawValue: "delegateObject") else {
throw DecoderKeyError.createKey
}
return userInfo[key] as? T
}
}