Swift 4 디코딩 시간까지 알 수 없는 키로 디코딩 가능
Swift 4 디코딩 프로토콜은 런타임까지 이름이 알려지지 않은 키를 포함하는 사전을 어떻게 처리합니까?예를 들어 다음과 같습니다.
[
{
"categoryName": "Trending",
"Trending": [
{
"category": "Trending",
"trailerPrice": "",
"isFavourit": null,
"isWatchlist": null
}
]
},
{
"categoryName": "Comedy",
"Comedy": [
{
"category": "Comedy",
"trailerPrice": "",
"isFavourit": null,
"isWatchlist": null
}
]
}
]
여기 사전 배열이 있습니다. 첫 번째 사전에는 키가 있습니다.categoryName
그리고.Trending
두 번째에는 키가 있습니다.categoryName
그리고.Comedy
의 값categoryName
key를 지정하면 두 번째 키의 이름이 나타납니다.디코드블을 사용해서 어떻게 표현하면 좋을까요?
중요한 것은, 이 명령어를 정의하는 방법」에 있습니다.CodingKeys
소유물.가장 흔한 일이지만enum
그것은 모든 것이 될 수 있다.CodingKey
프로토콜입니다.동적 키를 만들려면 정적 함수를 호출하면 됩니다.
struct Category: Decodable {
struct Detail: Decodable {
var category: String
var trailerPrice: String
var isFavorite: Bool?
var isWatchlist: Bool?
}
var name: String
var detail: Detail
private struct CodingKeys: CodingKey {
var intValue: Int?
var stringValue: String
init?(intValue: Int) { self.intValue = intValue; self.stringValue = "\(intValue)" }
init?(stringValue: String) { self.stringValue = stringValue }
static let name = CodingKeys.make(key: "categoryName")
static func make(key: String) -> CodingKeys {
return CodingKeys(stringValue: key)!
}
}
init(from coder: Decoder) throws {
let container = try coder.container(keyedBy: CodingKeys.self)
self.name = try container.decode(String.self, forKey: .name)
self.detail = try container.decode([Detail].self, forKey: .make(key: name)).first!
}
}
사용방법:
let jsonData = """
[
{
"categoryName": "Trending",
"Trending": [
{
"category": "Trending",
"trailerPrice": "",
"isFavourite": null,
"isWatchlist": null
}
]
},
{
"categoryName": "Comedy",
"Comedy": [
{
"category": "Comedy",
"trailerPrice": "",
"isFavourite": null,
"isWatchlist": null
}
]
}
]
""".data(using: .utf8)!
let categories = try! JSONDecoder().decode([Category].self, from: jsonData)
(변경했습니다.isFavourit
에의 JSON에서isFavourite
철자를 잘못 쓴 것 같아서요그렇지 않으면 코드를 쉽게 변경할 수 있습니다.)
CodingKeys 개체로 기능하는 커스텀 구조를 작성하여 지정한 키를 추출하도록 문자열로 초기화할 수 있습니다.
private struct CK : CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
따라서 원하는 키가 무엇인지 알게 되면 다음과 같이 말할 수 있습니다.init(from:)
덮어쓰기:
let key = // whatever the key name turns out to be
let con2 = try! decoder.container(keyedBy: CK.self)
self.unknown = try! con2.decode([Inner].self, forKey: CK(stringValue:key)!)
그 결과 디코더에서2개의 컨테이너를 만들었습니다.하나는 표준 CodingKeys 열거를 사용하여 값을 추출합니다."categoryName"
키 및 CK 구조를 사용하여 방금 배운 이름의 키 값을 추출하는 키도 있습니다.
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: CodingKeys.self)
self.categoryName = try! con.decode(String.self, forKey:.categoryName)
let key = self.categoryName
let con2 = try! decoder.container(keyedBy: CK.self)
self.unknown = try! con2.decode([Inner].self, forKey: CK(stringValue:key)!)
}
여기 디코딩 가능한 구조가 있습니다.
struct ResponseData : Codable {
let categoryName : String
let unknown : [Inner]
struct Inner : Codable {
let category : String
let trailerPrice : String
let isFavourit : String?
let isWatchList : String?
}
private enum CodingKeys : String, CodingKey {
case categoryName
}
private struct CK : CodingKey {
var stringValue: String
init?(stringValue: String) {
self.stringValue = stringValue
}
var intValue: Int?
init?(intValue: Int) {
return nil
}
}
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: CodingKeys.self)
self.categoryName = try! con.decode(String.self, forKey:.categoryName)
let key = self.categoryName
let con2 = try! decoder.container(keyedBy: CK.self)
self.unknown = try! con2.decode([Inner].self, forKey: CK(stringValue:key)!)
}
}
여기 테스트 베드가 있습니다.
let json = """
[
{
"categoryName": "Trending",
"Trending": [
{
"category": "Trending",
"trailerPrice": "",
"isFavourit": null,
"isWatchlist": null
}
]
},
{
"categoryName": "Comedy",
"Comedy": [
{
"category": "Comedy",
"trailerPrice": "",
"isFavourit": null,
"isWatchlist": null
}
]
}
]
"""
let myjson = try! JSONDecoder().decode(
[ResponseData].self,
from: json.data(using: .utf8)!)
print(myjson)
또, 델의 구조가 올바르게 채워지고 있는 것을 증명하는 인쇄 문구의 출력은, 다음과 같습니다.
[JustPlaying.ResponseData(
categoryName: "Trending",
unknown: [JustPlaying.ResponseData.Inner(
category: "Trending",
trailerPrice: "",
isFavourit: nil,
isWatchList: nil)]),
JustPlaying.ResponseData(
categoryName: "Comedy",
unknown: [JustPlaying.ResponseData.Inner(
category: "Comedy",
trailerPrice: "",
isFavourit: nil,
isWatchList: nil)])
]
물론 실생활에서 우리는 약간의 오류를 다루게 될 것이다, 의심할 여지 없이!
편집 나중에 깨달은 것은 (일부 CodeDifferent의 답변 덕분에) 컨테이너가 두 개 필요없다는 것입니다.CodingKeys 열거형을 제거할 수 있고, CK 구조체가 모든 작업을 수행할 수 있습니다.범용 키 메이커입니다.
init(from decoder: Decoder) throws {
let con = try! decoder.container(keyedBy: CK.self)
self.categoryName = try! con.decode(String.self, forKey:CK(stringValue:"categoryName")!)
let key = self.categoryName
self.unknown = try! con.decode([Inner].self, forKey: CK(stringValue:key)!)
}
내가 결국 이 json을 위해 생각해낸 것은 다음과 같다.
let json = """
{
"BTC_BCN":{
"last":"0.00000057",
"percentChange":"0.03636363",
"baseVolume":"47.08463318"
},
"BTC_BELA":{
"last":"0.00001281",
"percentChange":"0.07376362",
"baseVolume":"5.46595029"
}
}
""".data(using: .utf8)!
델은 다음과 같은 구조를 만듭니다.
struct Pair {
let name: String
let details: Details
struct Details: Codable {
let last, percentChange, baseVolume: String
}
}
디코딩:
if let pairsDictionary = try? JSONDecoder().decode([String: Pair.Details].self, from: json) {
var pairs: [Pair] = []
for (name, details) in pairsDictionary {
let pair = Pair(name: name, details: details)
pairs.append(pair)
}
print(pairs)
}
pair.details.baseVolume이 아닌 pair.baseVolume을 호출할 수도 있습니다.
struct Pair {
......
var baseVolume: String { return details.baseVolume }
......
또는 custom init을 씁니다.
struct Pair {
.....
let baseVolume: String
init(name: String, details: Details) {
self.baseVolume = details.baseVolume
......
언급URL : https://stackoverflow.com/questions/45598461/swift-4-decodable-with-keys-not-known-until-decoding-time
'source' 카테고리의 다른 글
TypeScript 업그레이드 후 Angular 컨트롤러 등록이 컴파일되지 않음 (0) | 2023.03.23 |
---|---|
JS 오브젝트에 대한 JSON 문자열 (0) | 2023.03.18 |
github API에서 링크 헤더를 해석하는 방법 (0) | 2023.03.18 |
JSON 개체를 버퍼로 변환하고 버퍼를 JSON 개체로 변환 (0) | 2023.03.18 |
WordPress 플러그인 현지화 (0) | 2023.03.18 |