-
-
Save mkv27/f293f281d785c617254f17981f893395 to your computer and use it in GitHub Desktop.
Hacky way of getting a custom GraphQL scalar for raw JSON to work in Apollo iOS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
typealias Raw = [String: JSONDecodable & JSONEncodable] | |
extension Dictionary: JSONDecodable { | |
public init(jsonValue value: JSONValue) throws { | |
guard let dictionary = forceBridgeFromObjectiveC(value) as? Dictionary else { | |
throw JSONDecodingError.couldNotConvert(value: value, to: Dictionary.self) | |
} | |
self = dictionary | |
} | |
} | |
extension Array: JSONDecodable { | |
public init(jsonValue value: JSONValue) throws { | |
guard let array = forceBridgeFromObjectiveC(value) as? Array else { | |
throw JSONDecodingError.couldNotConvert(value: value, to: Array.self) | |
} | |
self = array | |
} | |
} | |
// The types we get from `JSONSerialization` are Objective-C implementation types like | |
// `NSTaggedPointerString`, `__NSCFNumber`, `__NSSingleEntryDictionaryI`, etc. | |
// and although these get implicitly converted to Swift types in most contexts, | |
// they don’t allow us to check for protocol conformance. | |
// That means `NSTaggedPointerString` is not `JSONDecodable` and `JSONEncodable` | |
// for example, even though `String` is. Force casting to Swift types solves this. | |
private func forceBridgeFromObjectiveC(_ value: Any) -> Any { | |
switch value { | |
case is NSString: | |
return value as! String | |
// Can't use NSNumber here because we don't know whether to bridge to Bool, Int or Double. | |
// So instead we have to check possible conversions one by one. | |
// This isn't strictly correct because it converts 0 and 1 to Bool for example. | |
// See https://bugs.swift.org/browse/SR-5863 | |
case is Bool: | |
return value as! Bool | |
case is Int: | |
return value as! Int | |
case is Double: | |
return value as! Double | |
case is NSDictionary: | |
return Dictionary(uniqueKeysWithValues: (value as! NSDictionary).map { ( $0.key as! AnyHashable, forceBridgeFromObjectiveC($0.value)) }) | |
case is NSArray: | |
return (value as! NSArray).map { forceBridgeFromObjectiveC($0) } | |
default: | |
return value | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment