More details
- Xcode Version 10.3 (10G8), Swift 5
Decision
import Foundation // MARK: - CastingError struct CastingError: Error { let fromType: Any.Type let toType: Any.Type init<FromType, ToType>(fromType: FromType.Type, toType: ToType.Type) { self.fromType = fromType self.toType = toType } } extension CastingError: LocalizedError { var localizedDescription: String { return "Can not cast from \(fromType) to \(toType)" } } extension CastingError: CustomStringConvertible { var description: String { return localizedDescription } } // MARK: - Data cast extensions extension Data { func toDictionary(options: JSONSerialization.ReadingOptions = []) throws -> [String: Any] { return try to(type: [String: Any].self, options: options) } func to<T>(type: T.Type, options: JSONSerialization.ReadingOptions = []) throws -> T { guard let result = try JSONSerialization.jsonObject(with: self, options: options) as? T else { throw CastingError(fromType: type, toType: T.self) } return result } } // MARK: - String cast extensions extension String { func asJSON<T>(to type: T.Type, using encoding: String.Encoding = .utf8) throws -> T { guard let data = data(using: encoding) else { throw CastingError(fromType: type, toType: T.self) } return try data.to(type: T.self) } func asJSONToDictionary(using encoding: String.Encoding = .utf8) throws -> [String: Any] { return try asJSON(to: [String: Any].self, using: encoding) } } // MARK: - Dictionary cast extensions extension Dictionary { func toData(options: JSONSerialization.WritingOptions = []) throws -> Data { return try JSONSerialization.data(withJSONObject: self, options: options) } }
Usage
Usage
let value1 = try? data.toDictionary() let value2 = try? data.to(type: [String: Any].self) let value3 = try? data.to(type: [String: String].self) let value4 = try? string.asJSONToDictionary() let value5 = try? string.asJSON(to: [String: String].self)
Test sample
Remember to insert the solution code here.
func testDescriber(text: String, value: Any) { print("\n//////////////////////////////////////////") print("-- \(text)\n\n type: \(type(of: value))\n value: \(value)") } let json1: [String: Any] = ["key1" : 1, "key2": true, "key3" : ["a": 1, "b": 2], "key4": [1,2,3]] var jsonData = try? json1.toData() testDescriber(text: "Sample test of func toDictionary()", value: json1) if let data = jsonData { print(" Result: \(String(describing: try? data.toDictionary()))") } testDescriber(text: "Sample test of func to<T>() -> [String: Any]", value: json1) if let data = jsonData { print(" Result: \(String(describing: try? data.to(type: [String: Any].self)))") } testDescriber(text: "Sample test of func to<T>() -> [String] with cast error", value: json1) if let data = jsonData { do { print(" Result: \(String(describing: try data.to(type: [String].self)))") } catch { print(" ERROR: \(error)") } } let array = [1,4,5,6] testDescriber(text: "Sample test of func to<T>() -> [Int]", value: array) if let data = try? JSONSerialization.data(withJSONObject: array) { print(" Result: \(String(describing: try? data.to(type: [Int].self)))") } let json2 = ["key1": "a", "key2": "b"] testDescriber(text: "Sample test of func to<T>() -> [String: String]", value: json2) if let data = try? JSONSerialization.data(withJSONObject: json2) { print(" Result: \(String(describing: try? data.to(type: [String: String].self)))") } let jsonString = "{\"key1\": \"a\", \"key2\": \"b\"}" testDescriber(text: "Sample test of func to<T>() -> [String: String]", value: jsonString) print(" Result: \(String(describing: try? jsonString.asJSON(to: [String: String].self)))") testDescriber(text: "Sample test of func to<T>() -> [String: String]", value: jsonString) print(" Result: \(String(describing: try? jsonString.asJSONToDictionary()))") let wrongJsonString = "{\"key1\": \"a\", \"key2\":}" testDescriber(text: "Sample test of func to<T>() -> [String: String] with JSONSerialization error", value: jsonString) do { let json = try wrongJsonString.asJSON(to: [String: String].self) print(" Result: \(String(describing: json))") } catch { print(" ERROR: \(error)") }
Test log
////////////////////////////////////////// -- Sample test of func toDictionary() type: Dictionary<String, Any> value: ["key4": [1, 2, 3], "key2": true, "key3": ["a": 1, "b": 2], "key1": 1] Result: Optional(["key4": <__NSArrayI 0x600002a35380>( 1, 2, 3 ) , "key2": 1, "key3": { a = 1; b = 2; }, "key1": 1]) ////////////////////////////////////////// -- Sample test of func to<T>() -> [String: Any] type: Dictionary<String, Any> value: ["key4": [1, 2, 3], "key2": true, "key3": ["a": 1, "b": 2], "key1": 1] Result: Optional(["key4": <__NSArrayI 0x600002a254d0>( 1, 2, 3 ) , "key2": 1, "key1": 1, "key3": { a = 1; b = 2; }]) ////////////////////////////////////////// -- Sample test of func to<T>() -> [String] with cast error type: Dictionary<String, Any> value: ["key4": [1, 2, 3], "key2": true, "key3": ["a": 1, "b": 2], "key1": 1] ERROR: Can not cast from Array<String> to Array<String> ////////////////////////////////////////// -- Sample test of func to<T>() -> [Int] type: Array<Int> value: [1, 4, 5, 6] Result: Optional([1, 4, 5, 6]) ////////////////////////////////////////// -- Sample test of func to<T>() -> [String: String] type: Dictionary<String, String> value: ["key1": "a", "key2": "b"] Result: Optional(["key1": "a", "key2": "b"]) ////////////////////////////////////////// -- Sample test of func to<T>() -> [String: String] type: String value: {"key1": "a", "key2": "b"} Result: Optional(["key1": "a", "key2": "b"]) ////////////////////////////////////////// -- Sample test of func to<T>() -> [String: String] type: String value: {"key1": "a", "key2": "b"} Result: Optional(["key1": a, "key2": b]) ////////////////////////////////////////// -- Sample test of func to<T>() -> [String: String] with JSONSerialization error type: String value: {"key1": "a", "key2": "b"} ERROR: Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 21." UserInfo={NSDebugDescription=Invalid value around character 21.}