Merge branch 'develop' into 'release/10_0_0'
added userInfo into the Decoders See merge request BPHV_MIPS/mvm_core!210
This commit is contained in:
commit
f69dd7339c
@ -158,6 +158,8 @@
|
|||||||
D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */; };
|
D2DEDCB923C6400600C44CC4 /* UnitInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */; };
|
||||||
D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCBA23C65BC300C44CC4 /* Percent.swift */; };
|
D2DEDCBB23C65BC300C44CC4 /* Percent.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2DEDCBA23C65BC300C44CC4 /* Percent.swift */; };
|
||||||
D2E1FAD92260C3E400AEFD8C /* DelegateObject.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E1FAD82260C3E400AEFD8C /* DelegateObject.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 */; };
|
||||||
|
EA09CD99282BF83600A7835F /* DecodableDefault.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA09CD98282BF83600A7835F /* DecodableDefault.swift */; };
|
||||||
EA3B264C25FC0B7600008074 /* ModelHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */; };
|
EA3B264C25FC0B7600008074 /* ModelHandlerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
@ -307,6 +309,8 @@
|
|||||||
D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitInterval.swift; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
||||||
|
EA09CD98282BF83600A7835F /* DecodableDefault.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DecodableDefault.swift; sourceTree = "<group>"; };
|
||||||
EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHandlerProtocol.swift; sourceTree = "<group>"; };
|
EA3B264B25FC0B7600008074 /* ModelHandlerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelHandlerProtocol.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
@ -435,6 +439,7 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
946EE1AA237B5C940036751F /* Decoder.swift */,
|
946EE1AA237B5C940036751F /* Decoder.swift */,
|
||||||
|
EA09CD61282ACDDB00A7835F /* Decoder+UserInfo.swift */,
|
||||||
946EE1B3237B619D0036751F /* Encoder.swift */,
|
946EE1B3237B619D0036751F /* Encoder.swift */,
|
||||||
0A42538E23F3414800554656 /* Codable+Helpers.swift */,
|
0A42538E23F3414800554656 /* Codable+Helpers.swift */,
|
||||||
);
|
);
|
||||||
@ -685,6 +690,7 @@
|
|||||||
D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */,
|
D2DEDCB623C63F3B00C44CC4 /* Clamping.swift */,
|
||||||
D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */,
|
D2DEDCB823C6400600C44CC4 /* UnitInterval.swift */,
|
||||||
D2DEDCBA23C65BC300C44CC4 /* Percent.swift */,
|
D2DEDCBA23C65BC300C44CC4 /* Percent.swift */,
|
||||||
|
EA09CD98282BF83600A7835F /* DecodableDefault.swift */,
|
||||||
);
|
);
|
||||||
path = PropertyWrappers;
|
path = PropertyWrappers;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -911,6 +917,8 @@
|
|||||||
AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */,
|
AFEA17A9209B6A1C00BC6740 /* MVMCoreBlockOperation.m in Sources */,
|
||||||
AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */,
|
AF43A70A1FC4F415008E9347 /* MVMCoreCache.m in Sources */,
|
||||||
AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */,
|
AF43A6FF1FBE3252008E9347 /* Reachability.m in Sources */,
|
||||||
|
EA09CD62282ACDDB00A7835F /* Decoder+UserInfo.swift in Sources */,
|
||||||
|
EA09CD99282BF83600A7835F /* DecodableDefault.swift in Sources */,
|
||||||
01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */,
|
01C851D123CF97FE0021F976 /* ActionBackModel.swift in Sources */,
|
||||||
D27073D125BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift in Sources */,
|
D27073D125BB844B001C7246 /* MVMCoreActionDelegateProtocol+Extension.swift in Sources */,
|
||||||
AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */,
|
AFBB96921FBA3A9A0008D868 /* MVMCoreNavigationOperation.m in Sources */,
|
||||||
|
|||||||
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? {
|
func getClientParameterModel(_ clientParameters: [String: Any]) throws -> ClientParameterModel? {
|
||||||
let data = try JSONSerialization.data(withJSONObject: clientParameters)
|
let data = try JSONSerialization.data(withJSONObject: clientParameters)
|
||||||
return try JSONDecoder().decode(ClientParameterModel.self, from: data)
|
return try JSONDecoder.create().decode(ClientParameterModel.self, from: data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample clientParameters
|
/// Sample clientParameters
|
||||||
|
|||||||
113
MVMCore/MVMCore/Models/Extensions/Decoder+UserInfo.swift
Normal file
113
MVMCore/MVMCore/Models/Extensions/Decoder+UserInfo.swift
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
//
|
||||||
|
// Decoder+UserInfo.swift
|
||||||
|
// MVMCore
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 5/10/22.
|
||||||
|
// Copyright © 2022 myverizon. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
extension CodingUserInfoKey {
|
||||||
|
public static let delegateObjectKey = CodingUserInfoKey(rawValue: "delegateObject")!
|
||||||
|
public 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<T: DelegateObject>(delegateObject: T) {
|
||||||
|
add(value: delegateObject, for: .delegateObjectKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
/// Adds a key/value to the decoder for use in the model initializers.
|
||||||
|
func add(value: Any, for key: CodingUserInfoKey) {
|
||||||
|
userInfo.updateValue(value, forKey: key)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper method to initialize a JSONDecoder
|
||||||
|
/// - Parameter delegateObject: Delegate Object
|
||||||
|
/// - Returns: JSONDecoder
|
||||||
|
public class func create(with delegateObject: DelegateObject? = nil) -> 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 }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@ extension JSONDecoder: AnyDecoder {}
|
|||||||
extension PropertyListDecoder: AnyDecoder {}
|
extension PropertyListDecoder: AnyDecoder {}
|
||||||
|
|
||||||
extension Data {
|
extension Data {
|
||||||
public func decode<T: Decodable>(using decoder: AnyDecoder = JSONDecoder(), delegateObject: DelegateObject? = nil) throws -> T {
|
public func decode<T: Decodable>(using decoder: AnyDecoder = JSONDecoder.create(), delegateObject: DelegateObject? = nil) throws -> T {
|
||||||
if let decoder = decoder as? JSONDecoder {
|
if let decoder = decoder as? JSONDecoder {
|
||||||
return try decoder.decode(T.self, from: self, delegateObject: delegateObject)
|
return try decoder.decode(T.self, from: self, delegateObject: delegateObject)
|
||||||
} else {
|
} else {
|
||||||
@ -25,6 +25,19 @@ 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 context == nil {
|
||||||
|
add(value: DecodingContext(), for: .contextKey)
|
||||||
|
}
|
||||||
|
if let delegateObject = delegateObject {
|
||||||
|
add(value: delegateObject, for: .delegateObjectKey)
|
||||||
|
}
|
||||||
|
return try decode(T.self, from: data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension KeyedDecodingContainerProtocol {
|
extension KeyedDecodingContainerProtocol {
|
||||||
public func decode<T: Decodable>(forKey key: Key) throws -> T {
|
public func decode<T: Decodable>(forKey key: Key) throws -> T {
|
||||||
return try decode(T.self, forKey: key)
|
return try decode(T.self, forKey: key)
|
||||||
@ -42,7 +55,8 @@ extension Decodable {
|
|||||||
public static func decode(jsonDict: [String: Any], delegateObject: DelegateObject? = nil) throws -> Self {
|
public static func decode(jsonDict: [String: Any], delegateObject: DelegateObject? = nil) throws -> Self {
|
||||||
let jsonData = try JSONSerialization.data(withJSONObject: jsonDict)
|
let jsonData = try JSONSerialization.data(withJSONObject: jsonDict)
|
||||||
do {
|
do {
|
||||||
return try jsonData.decode(delegateObject: delegateObject)
|
let decoder = JSONDecoder.create(with: delegateObject)
|
||||||
|
return try jsonData.decode(using: decoder)
|
||||||
} catch {
|
} catch {
|
||||||
throw JSONError.other(error: error)
|
throw JSONError.other(error: error)
|
||||||
}
|
}
|
||||||
@ -64,35 +78,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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@ -0,0 +1,87 @@
|
|||||||
|
//
|
||||||
|
// DecoderDefault.swift
|
||||||
|
// MVMCore
|
||||||
|
//
|
||||||
|
// Created by Matt Bruce on 5/11/22.
|
||||||
|
// Copyright © 2022 myverizon. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
/// https://www.swiftbysundell.com/tips/default-decoding-values/
|
||||||
|
/// This code is used for Decodable objects that allow Default Values to be added.
|
||||||
|
public protocol DecodableDefaultSource {
|
||||||
|
associatedtype Value: Decodable
|
||||||
|
static var defaultValue: Value { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum DecodableDefault {}
|
||||||
|
|
||||||
|
extension DecodableDefault {
|
||||||
|
@propertyWrapper
|
||||||
|
public struct Wrapper<Source: DecodableDefaultSource> {
|
||||||
|
public typealias Value = Source.Value
|
||||||
|
public var wrappedValue = Source.defaultValue
|
||||||
|
public init() {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault.Wrapper: Decodable {
|
||||||
|
public init(from decoder: Decoder) throws {
|
||||||
|
let container = try decoder.singleValueContainer()
|
||||||
|
wrappedValue = try container.decode(Value.self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension KeyedDecodingContainer {
|
||||||
|
public func decode<T>(_ type: DecodableDefault.Wrapper<T>.Type,
|
||||||
|
forKey key: Key) throws -> DecodableDefault.Wrapper<T> {
|
||||||
|
try decodeIfPresent(type, forKey: key) ?? .init()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault {
|
||||||
|
public typealias Source = DecodableDefaultSource
|
||||||
|
public typealias List = Decodable & ExpressibleByArrayLiteral
|
||||||
|
public typealias Map = Decodable & ExpressibleByDictionaryLiteral
|
||||||
|
|
||||||
|
public enum Sources {
|
||||||
|
public enum True: Source {
|
||||||
|
public static var defaultValue: Bool { true }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum False: Source {
|
||||||
|
public static var defaultValue: Bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EmptyString: Source {
|
||||||
|
public static var defaultValue: String { "" }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EmptyList<T: List>: Source {
|
||||||
|
public static var defaultValue: T { [] }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum EmptyMap<T: Map>: Source {
|
||||||
|
public static var defaultValue: T { [:] }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault {
|
||||||
|
public typealias True = Wrapper<Sources.True>
|
||||||
|
public typealias False = Wrapper<Sources.False>
|
||||||
|
public typealias EmptyString = Wrapper<Sources.EmptyString>
|
||||||
|
public typealias EmptyList<T: List> = Wrapper<Sources.EmptyList<T>>
|
||||||
|
public typealias EmptyMap<T: Map> = Wrapper<Sources.EmptyMap<T>>
|
||||||
|
}
|
||||||
|
|
||||||
|
extension DecodableDefault.Wrapper: Equatable where Value: Equatable {}
|
||||||
|
extension DecodableDefault.Wrapper: Hashable where Value: Hashable {}
|
||||||
|
|
||||||
|
extension DecodableDefault.Wrapper: Encodable where Value: Encodable {
|
||||||
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
var container = encoder.singleValueContainer()
|
||||||
|
try container.encode(wrappedValue)
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user