         }
     }
 
+    fileprivate func unbox<T>(_ value: Any, as type: _JSONStringDictionaryDecodableMarker.Type) throws -> T? {
+        guard !(value is NSNull) else { return nil }
+
+        var result = [String : Any]()
+        guard let dict = value as? NSDictionary else {
+            throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
+        }
+        let elementType = type.elementType
+        for (key, value) in dict {
+            let key = key as! String
+            self.codingPath.append(_JSONKey(stringValue: key, intValue: nil))
+            defer { self.codingPath.removeLast() }
+
+            result[key] = try unbox_(value, as: elementType)
+        }
+
+        return result as? T
+    }
+
     fileprivate func unbox<T : Decodable>(_ value: Any, as type: T.Type) throws -> T? {
-        let decoded: T
+        return try unbox_(value, as: type) as? T
+    }
+
+    fileprivate func unbox_(_ value: Any, as type: Decodable.Type) throws -> Any? {
         #if DEPLOYMENT_RUNTIME_SWIFT
         // Bridging differences require us to split implementations here
-        if T.self == Date.self {
+        if type == Date.self {
             guard let date = try self.unbox(value, as: Date.self) else { return nil }
-            decoded = date as! T
-        } else if T.self == Data.self {
+            return date
+        } else if type == Data.self {
             guard let data = try self.unbox(value, as: Data.self) else { return nil }
-            decoded = data as! T
-        } else if T.self == URL.self {
+            return data
+        } else if type == URL.self {
             guard let urlString = try self.unbox(value, as: String.self) else {
                 return nil
             }

        }
    }

    fileprivate func box<T : Encodable>(_ value: T) throws -> NSObject {
        return try self.box_(value) ?? NSDictionary()
    }

    // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want.
    fileprivate func box_<T : Encodable>(_ value: T) throws -> NSObject? {
        #if DEPLOYMENT_RUNTIME_SWIFT
        if T.self == Date.self {
            // Respect Date encoding strategy
            return try self.box((value as! Date))
        } else if T.self == Data.self {
            // Respect Data encoding strategy
            return try self.box((value as! Data))
        } else if T.self == URL.self {
            // Encode URLs as single strings.
            return self.box((value as! URL).absoluteString)
        } else if T.self == Decimal.self {
            // JSONSerialization can consume NSDecimalNumber values.
            return NSDecimalNumber(decimal: value as! Decimal)
        }
        
        #else
        if T.self == Date.self || T.self == NSDate.self {
            // Respect Date encoding strategy
            return try self.box((value as! Date))
        } else if T.self == Data.self || T.self == NSData.self {
            // Respect Data encoding strategy
            return try self.box((value as! Data))
        } else if T.self == URL.self || T.self == NSURL.self {
            // Encode URLs as single strings.
            return self.box((value as! URL).absoluteString)
        } else if T.self == Decimal.self {
            // JSONSerialization can consume NSDecimalNumber values.
            return NSDecimalNumber(decimal: value as! Decimal)
        }
        #endif
        

                                                                        debugDescription: "Invalid URL string."))
            }
            
            return url
        } else if type == Decimal.self || type == NSDecimalNumber.self {
            return try self.unbox(value, as: Decimal.self)
        } else if let stringKeyedDictType = type as? _JSONStringDictionaryDecodableMarker.Type {
            return try self.unbox(value, as: stringKeyedDictType)
        } else {
            self.storage.push(container: value)
            defer { self.storage.popContainer() }
            return try type.init(from: self)
        }
        #endif
    }
}

