ObjectMapper - отображать словарь JSON как вложенный объект - PullRequest
0 голосов
/ 12 марта 2019

Я пытаюсь использовать ObjectMapper для получения ответа JSON.Пока мой ответ выглядит следующим образом:

{
  "paramsStructure": [
    {
      "tiles": {
        "0": {
          "layout": {
            "column": 0,
            "colSpan": "1",
            "rowSpan": "1",
            "row": 0
          },
          "type": "2"
        },
        "1": {
          "layout": {
            "column": 1,
            "colSpan": "1",
            "rowSpan": "1",
            "row": 0
          },
          "type": "2"
        }
      },
      "title": "...",
      "rowCount": "4",
      "colCount": "2",
      "key": "...",
      "icon": "..."
    }
  ]
}

До сих пор я создал StructuresObject для всей paramsStructure и вложенной коллекции объекта Single Structure.Теперь я хочу отобразить плитки в коллекцию объектов TileStructure, вложенную в объект Structure, выглядящий следующим образом.

class SingleStructure : Mappable{

    var columns: Int = 0
    var title: String = ""
    var key: String = ""
    var icon: String = ""
    var tilesStructure : [Int: TileStructure]?

    required init?(map: Map) {

    }

    func mapping(map: Map) {
        title <- map["title"]
        key <- map["key"]
        icon <- map["icon"]
        columns <- (map["colCount"], TransformOf<Int, String>(
            fromJSON: {item in return Int(item!)},
            toJSON: {_ in return "$0"}))


        //need here parsing of tilesStructure
     }
}

Мне в основном нужно сопоставить этот словарь плиток JSON с [Int: TileStructure], где ключ - это ключ словаря, а TileStructure - TileStructure.является сопоставляемым объектом, содержащим атрибуты "layout" и "type".

Заранее благодарен за помощь:)

EDIT !!!

Я пробовал подход denis_lor, но когдаЯ запускаю анализ данных из RxAlamofire, я получаю следующее исключение:

keyNotFound(CodingKeys(stringValue: "tiles", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"tiles\", intValue: nil) (\"tiles\").", underlyingError: nil))

Вот как я называю запрос

 return RxAlamofire.requestData(.get, GlobalSettings.GET_DEVICE_MAIN_STRUCTURE, parameters: parameters, headers: headers)
        .debug()

        .mapObject(type: ParamsStructure.self)

И это мой объект сопоставления:

extension ObservableType {

public func mapObject<T: Codable>(type: T.Type) -> Observable<T> {
    return flatMap { data -> Observable<T> in
        let responseTuple = data as? (HTTPURLResponse, Data)

        guard let jsonData = responseTuple?.1 else {
            throw NSError(
                domain: "",
                code: -1,
                userInfo: [NSLocalizedDescriptionKey: "Could not decode object"]
            )
        }

        let decoder = JSONDecoder()

        let object = try decoder.decode(T.self, from: jsonData)

        return Observable.just(object)
    }
}

}

Я думаю, что проблема, возможно, заключается в кодировании, и это то, что создает те escape "\", что падает на несоответствие ключей.

1 Ответ

1 голос
/ 12 марта 2019

Ключ к работе со структурой json, где у вас есть динамические ключи, заключается в использовании Dictionary, как я сделал с [String:Tile].

. Вы можете попробовать с новым Ciftable Swift4 * 1006.*:

import Foundation

public struct ResultParamsStructure: Codable {
    public var paramsStructure: [ParamsStructure] = []

    enum CodingKeys: String, CodingKey {
        case paramsStructure = "paramsStructure"
    }
}

public struct ParamsStructure: Codable {
    public var tiles: [String:Tile] = [:]
    public var title: String = ""
    public var rowCount: String = ""
    public var colCount: String = ""
    public var key: String = ""
    public var icon: String = ""

    enum CodingKeys: String, CodingKey {
        case tiles = "tiles"
        case title = "title"
        case rowCount = "rowCount"
        case colCount = "colCount"
        case key = "key"
        case icon = "icon"
    }
}

public struct Tile: Codable {
    public var layout: Layout?
    public var type: String = ""

    enum CodingKeys: String, CodingKey {
        case layout = "layout"
        case type = "type"
    }
}

public struct Layout: Codable {
    public var column: Int = 0
    public var colSpan: String = ""
    public var rowSpan: String = ""
    public var row: Int = 0

    enum CodingKeys: String, CodingKey {
        case column = "column"
        case colSpan = "colSpan"
        case rowSpan = "rowSpan"
        case row = "row"
    }
}

let jsonString = """
{
  "paramsStructure": [
    {
      "tiles": {
        "0": {
          "layout": {
            "column": 0,
            "colSpan": "1",
            "rowSpan": "1",
            "row": 0
          },
          "type": "2"
        },
        "1": {
          "layout": {
            "column": 1,
            "colSpan": "1",
            "rowSpan": "1",
            "row": 0
          },
          "type": "2"
        }
      },
      "title": "...",
      "rowCount": "4",
      "colCount": "2",
      "key": "...",
      "icon": "..."
    }
  ]
}
"""

let json = jsonString.data(using: .utf8)!

let resultParamsStructure = try? JSONDecoder().decode(ResultParamsStructure.self, from: json)

print(resultParamsStructure?.paramsStructure[0].tiles.keys)
print(resultParamsStructure?.paramsStructure[0].tiles["1"]?.layout?.colSpan)
//# Optional(Dictionary.Keys(["0", "1"]))
//# Optional("1")

Вы можете попробовать приведенный выше код здесь: http://online.swiftplayground.run/

...