(Added swift users as CC) 2017-06-24 3:47 GMT+09:00 Masaki Haga <hgmsk1...@gmail.com>:
> Hi Tony, > > Got it. Thank you very much for taking time for this. > > 2017-06-24 1:40 GMT+09:00 Tony Parker <anthony.par...@apple.com>: > >> Hi Masaki, >> >> Thanks for the additional info. I have a slightly different idea on how >> to approach this which I think will be more performant. Let me work on that >> and get back to you. >> >> - Tony >> >> >> On Jun 22, 2017, at 7:51 PM, Masaki Haga <hgmsk1...@gmail.com> wrote: >> >> Hi Tony, >> >> Thank you very much for replying. Let me clarify what I was saying. >> >> Let’s say, we have a JSON like this: >> >> { >> "badge": 1, >> "content_available": false, >> "mutable_content": false >> } >> >> and to decode this JSON, we have to have a Codable model like below with >> custom CodingKeys enum: >> >> struct APS: Codable { >> enum CodingKeys: String, CodingKey { >> case badge = "badge" >> case contentAvailable = "content_available" >> case mutableContent = "mutable_content" >> } >> >> var badge: Int >> var contentAvailable: Bool >> var mutableContent: Bool >> } >> >> This is a very small JSON so it is not hard to write this custom enum. >> However, it is very cumbersome to define this enum in all of the >> pre-existing models in our project to be able to decoded by Decodable and >> we rather prefer just to have a model something like this: >> >> struct APS: Codable { >> var badge: Int >> var contentAvailable: Bool >> var mutableContent: Bool >> } >> >> To be able to decode this model with JSONDecoder, I wrote a JSON >> converter like this: >> >> extension String { >> var camelcased: String { >> return self >> .components(separatedBy: "_") >> .enumerated() >> .map { 0 == $0.offset ? $0.element : $0.element.capitalized } >> .joined() >> } >> } >> // This extension above was referenced from an article written in >> Japanese: http://qiita.com/takasek/items/77955948fe283758ee55 >> >> struct JSONCaseConverter { >> public static func process(_ JSONObject: Any) -> Any { >> if var dict = JSONObject as? [String: Any] { >> for (key, value) in dict { >> dict[key.camelcased] = process(value) >> dict.removeValue(forKey: key) >> } >> return dict >> } else if let array = JSONObject as? [Any] { >> return array.map(process) >> } else { >> return JSONObject >> } >> } >> } >> >> Basically, this JSONCaseConverter go though all the keys in a JSON and >> convert the key from snake-case to camel-case so that the JSON can be >> decoded directly with the model without custom CodingKeys enum. >> >> And then if we have a Data type JSON object (typically got from >> URLSession.dataTask) and want to do some processing like this and decode >> with JSONDecoder, we need to do: >> >> 1. Serialize Data object with JSONSerialization.jsonObject(with:) and >> get Any type JSON Object >> 2. do some processing to the Any type JSON Object >> 3. Serialize Any type Object with JSONSerialization.data(withJSONObject:) >> and get Data type JSON Object back. >> 4. and then call JSONDecoder.decode(). >> >> However, JSONSerialization.jsonObject(with:) is called again in >> JSONDecoder.decode() implementation so there is a computational redundancy. >> >> Because I have already seen several this camel-case vs snake-case >> discussion in some places including Swift Evolution, I guess not a small >> number of developers will take the similar apploach ( I understand >> automatic key renaming could be a unsafe operation and this is just my >> personal opinion). >> >> Anyways, I was wondering if there is any way to opt-out the >> JSONSerialization.jsonObject(with:) in JSONDecoder.decode(). And if not, >> is it a good idea to have one more API such as `decode<T>(_ type: T.Type, >> from JSONObject: Any)` which I think gives more flexibility to the API? >> >> Regards, >> - Masaki >> >> 2017-06-23 8:01 GMT+09:00 Tony Parker <anthony.par...@apple.com>: >> >>> Hi Masaki, >>> >>> Do you mean that you are going through the JSON as a string value and >>> changing the keys, then you want to pass this re-written JSON to the >>> decoder? >>> >>> - Tony >>> >>> On Jun 21, 2017, at 6:58 PM, Masaki Haga via swift-users < >>> swift-users@swift.org> wrote: >>> >>> Hi Swift-Users, >>> >>> I was wondering if there is any way to decode JSON from Any type JSON >>> Object using `JSONDecoder`, not from Data type object. >>> >>> Currently, `JSONDecoder` has only one decode function which decodes Data >>> type object to `Decodable`. Inside the function, it serializes Data object >>> to Any Type JSON Object using `JSONSerialization` and pass it into >>> `_JSONDecoder(referencing:, options:)` (Refer JSONEncoder.swift#874). >>> >>> As discussed in some of other threads such as "SE-0166: Swift Archival & >>> Serialization", the default implementation of JSONDecoder or Decodable >>> protocol doesn’t allow to decode from one format to another format (such as >>> snake-case to camel-case), we need to implement custom CodingKey enums. >>> However, in our project, to parse the server API JSON response with >>> snake-case, declaring custom CodingKey enums for all the pre-existing >>> models is almost impossible and very inefficient, so I decided to covert >>> all the JSON keys from snake-case to camel-case, and then pass it into >>> `JSONDecoder.decode`. To achieve this, we need to convert the Data object >>> resulted from `URLSession.task` to Any type JSON Object using >>> `JSONSerialization`, do the conversion from snake-case to camel-case and >>> then convert back to Data type and then pass to `JSONDecoder.decode` which >>> looks very redundant because the function uses `JSONSerialization` inside >>> of it as mentioned above. If there is a function like below, we can get rid >>> of this redundant call of `JSONSerialization`. >>> >>> ``` >>> func decode<T : Decodable>(_ type: T.Type, from JSONObject: Any) throws >>> -> T >>> ``` >>> >>> Sorry if I am misunderstanding the new API but is there any way to >>> decode `Decodable` directly from Any type JSON Object? >>> >>> If not, I think adding the function aforementioned and giving an ability >>> to opt-out this JSON serialization call would give more flexibility to the >>> API in my humble opinion. >>> >>> Thank you for reading. >>> >>> All the best, >>> - Masaki >>> _______________________________________________ >>> swift-users mailing list >>> swift-users@swift.org >>> https://lists.swift.org/mailman/listinfo/swift-users >>> >>> >>> >> >> >
_______________________________________________ swift-users mailing list swift-users@swift.org https://lists.swift.org/mailman/listinfo/swift-users