Как декодировать свойство с типом словаря JSON в декодируемом протоколе Swift 4

104

Скажем, у меня есть Customerтип данных, который содержит metadataсвойство, которое может содержать любой словарь JSON в объекте клиента.

struct Customer {
  let id: String
  let email: String
  let metadata: [String: Any]
}

{  
  "object": "customer",
  "id": "4yq6txdpfadhbaqnwp3",
  "email": "john.doe@example.com",
  "metadata": {
    "link_id": "linked-id",
    "buy_count": 4
  }
}

metadataСвойство может быть любой произвольный объект JSON на карте.

Прежде чем я смогу преобразовать свойство из десериализованного JSON, NSJSONDeserializationно с новым Decodableпротоколом Swift 4 , я все еще не могу придумать способ сделать это.

Кто-нибудь знает, как этого добиться в Swift 4 с протоколом Decodable?

Питифонг Фонгпаттранонт
источник

Ответы:

90

Вдохновленный этой сутью , я написал несколько расширений для UnkeyedDecodingContainerи KeyedDecodingContainer. Вы можете найти ссылку на мою суть здесь . Используя этот код, вы теперь можете декодировать любой Array<Any>или Dictionary<String, Any>знакомый синтаксис:

let dictionary: [String: Any] = try container.decode([String: Any].self, forKey: key)

или

let array: [Any] = try container.decode([Any].self, forKey: key)

Изменить: я обнаружил одно предостережение, которое заключается в декодировании массива словарей [[String: Any]]. Требуемый синтаксис выглядит следующим образом. Скорее всего, вы захотите выдать ошибку вместо принудительного приведения:

let items: [[String: Any]] = try container.decode(Array<Any>.self, forKey: .items) as! [[String: Any]]

РЕДАКТИРОВАТЬ 2: если вы просто хотите преобразовать весь файл в словарь, вам лучше придерживаться api из JSONSerialization, так как я не нашел способа расширить сам JSONDecoder для прямого декодирования словаря.

guard let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else {
  // appropriate error handling
  return
}

Расширения

// Inspired by https://gist.github.com/mbuchetics/c9bc6c22033014aa0c550d3b4324411a

struct JSONCodingKeys: CodingKey {
    var stringValue: String

    init?(stringValue: String) {
        self.stringValue = stringValue
    }

    var intValue: Int?

    init?(intValue: Int) {
        self.init(stringValue: "\(intValue)")
        self.intValue = intValue
    }
}


extension KeyedDecodingContainer {

    func decode(_ type: Dictionary<String, Any>.Type, forKey key: K) throws -> Dictionary<String, Any> {
        let container = try self.nestedContainer(keyedBy: JSONCodingKeys.self, forKey: key)
        return try container.decode(type)
    }

    func decodeIfPresent(_ type: Dictionary<String, Any>.Type, forKey key: K) throws -> Dictionary<String, Any>? {
        guard contains(key) else { 
            return nil
        }
        guard try decodeNil(forKey: key) == false else { 
            return nil 
        }
        return try decode(type, forKey: key)
    }

    func decode(_ type: Array<Any>.Type, forKey key: K) throws -> Array<Any> {
        var container = try self.nestedUnkeyedContainer(forKey: key)
        return try container.decode(type)
    }

    func decodeIfPresent(_ type: Array<Any>.Type, forKey key: K) throws -> Array<Any>? {
        guard contains(key) else {
            return nil
        }
        guard try decodeNil(forKey: key) == false else { 
            return nil 
        }
        return try decode(type, forKey: key)
    }

    func decode(_ type: Dictionary<String, Any>.Type) throws -> Dictionary<String, Any> {
        var dictionary = Dictionary<String, Any>()

        for key in allKeys {
            if let boolValue = try? decode(Bool.self, forKey: key) {
                dictionary[key.stringValue] = boolValue
            } else if let stringValue = try? decode(String.self, forKey: key) {
                dictionary[key.stringValue] = stringValue
            } else if let intValue = try? decode(Int.self, forKey: key) {
                dictionary[key.stringValue] = intValue
            } else if let doubleValue = try? decode(Double.self, forKey: key) {
                dictionary[key.stringValue] = doubleValue
            } else if let nestedDictionary = try? decode(Dictionary<String, Any>.self, forKey: key) {
                dictionary[key.stringValue] = nestedDictionary
            } else if let nestedArray = try? decode(Array<Any>.self, forKey: key) {
                dictionary[key.stringValue] = nestedArray
            }
        }
        return dictionary
    }
}

extension UnkeyedDecodingContainer {

    mutating func decode(_ type: Array<Any>.Type) throws -> Array<Any> {
        var array: [Any] = []
        while isAtEnd == false {
            // See if the current value in the JSON array is `null` first and prevent infite recursion with nested arrays.
            if try decodeNil() {
                continue
            } else if let value = try? decode(Bool.self) {
                array.append(value)
            } else if let value = try? decode(Double.self) {
                array.append(value)
            } else if let value = try? decode(String.self) {
                array.append(value)
            } else if let nestedDictionary = try? decode(Dictionary<String, Any>.self) {
                array.append(nestedDictionary)
            } else if let nestedArray = try? decode(Array<Any>.self) {
                array.append(nestedArray)
            }
        }
        return array
    }

    mutating func decode(_ type: Dictionary<String, Any>.Type) throws -> Dictionary<String, Any> {

        let nestedContainer = try self.nestedContainer(keyedBy: JSONCodingKeys.self)
        return try nestedContainer.decode(type)
    }
}
болтун
источник
Интересно, я попробую эту суть и сообщу вам результат @loudmouth
Pitiphong Phongpattranont
@PitiphongPhongpattranont у вас сработал этот код?
болтун
1
@JonBrooks последнего условия в в UnkeyedDecodingContainer«S decode(_ type: Array<Any>.Type) throws -> Array<Any>проверяет для вложенного массива. Итак, если у вас есть структура данных, которая выглядит следующим образом: [true, 452.0, ["a", "b", "c"] ] она будет извлекать вложенный ["a", "b", "c"]массив. decodeМетода А. Н. UnkeyedDecodingContainer«хлопков» от элемента из контейнера. Это не должно вызывать бесконечную рекурсию.
крикун
1
@loudmouth можно иметь нулевые значения для ключей в формате JSON: {"array": null}. Таким образом, вы guard contains(key)пройдете, но через несколько строк при попытке декодирования нулевого значения для ключа «массив» произойдет сбой. Поэтому перед вызовом лучше добавить еще одно условие, чтобы проверить, действительно ли значение не равно нулю decode.
chebur
2
Я нашел исправление: Вместо } else if let nestedArray = try? decode(Array<Any>.self, forKey: key)попытки:} else if var nestedContainer = try? nestedUnkeyedContainer(), let nestedArray = try? nestedContainer.decode(Array<Any>.self) {
Джон Брукс
23

Я тоже играл с этой проблемой и, наконец, написал простую библиотеку для работы с «общими типами JSON» . (Где «общий» означает «без заранее известной структуры».) Основной момент - это представление универсального JSON с конкретным типом:

public enum JSON {
    case string(String)
    case number(Float)
    case object([String:JSON])
    case array([JSON])
    case bool(Bool)
    case null
}

Затем этот тип может реализовать Codableи Equatable.

зул
источник
13

Вы можете создать структуру метаданных, которая подтверждает Decodableпротокол и использовать JSONDecoderкласс для создания объекта из данных, используя метод декодирования, как показано ниже.

let json: [String: Any] = [
    "object": "customer",
    "id": "4yq6txdpfadhbaqnwp3",
    "email": "john.doe@example.com",
    "metadata": [
        "link_id": "linked-id",
        "buy_count": 4
    ]
]

struct Customer: Decodable {
    let object: String
    let id: String
    let email: String
    let metadata: Metadata
}

struct Metadata: Decodable {
    let link_id: String
    let buy_count: Int
}

let data = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)

let decoder = JSONDecoder()
do {
    let customer = try decoder.decode(Customer.self, from: data)
    print(customer)
} catch {
    print(error.localizedDescription)
}
Сухит Патил
источник
10
Нет, не могу, так как не знаю структуры metadataзначения. Это может быть любой произвольный объект.
Pitiphong Phongpattranont
Вы имеете в виду, что это может быть тип массива или словаря?
Сухит Патил
не могли бы вы привести пример или добавить дополнительные пояснения о структуре метаданных
Сухит Патил
2
Значением metadataможет быть любой объект JSON. Так что это может быть пустой словарь или любой другой словарь. "метаданные": {} "метаданные": {user_id: "id"} "метаданные": {preference: {shows_value: true, language: "en"}} и т. д.
Питифонг Фонгпаттранонт
один из возможных вариантов - использовать все параметры в структуре метаданных в качестве дополнительных и перечислить все возможные значения в структуре метаданных, например struct metadata {var user_id: String? предпочтение var: String? }
Сухит Патил
8

Я пришел с немного другим решением.

Предположим, у нас есть нечто большее, чем просто [String: Any]анализируемый объект, если Any может быть массивом, вложенным словарем или словарем массивов.

Что-то вроде этого:

var json = """
{
  "id": 12345,
  "name": "Giuseppe",
  "last_name": "Lanza",
  "age": 31,
  "happy": true,
  "rate": 1.5,
  "classes": ["maths", "phisics"],
  "dogs": [
    {
      "name": "Gala",
      "age": 1
    }, {
      "name": "Aria",
      "age": 3
    }
  ]
}
"""

Что ж, это мое решение:

public struct AnyDecodable: Decodable {
  public var value: Any

  private struct CodingKeys: CodingKey {
    var stringValue: String
    var intValue: Int?
    init?(intValue: Int) {
      self.stringValue = "\(intValue)"
      self.intValue = intValue
    }
    init?(stringValue: String) { self.stringValue = stringValue }
  }

  public init(from decoder: Decoder) throws {
    if let container = try? decoder.container(keyedBy: CodingKeys.self) {
      var result = [String: Any]()
      try container.allKeys.forEach { (key) throws in
        result[key.stringValue] = try container.decode(AnyDecodable.self, forKey: key).value
      }
      value = result
    } else if var container = try? decoder.unkeyedContainer() {
      var result = [Any]()
      while !container.isAtEnd {
        result.append(try container.decode(AnyDecodable.self).value)
      }
      value = result
    } else if let container = try? decoder.singleValueContainer() {
      if let intVal = try? container.decode(Int.self) {
        value = intVal
      } else if let doubleVal = try? container.decode(Double.self) {
        value = doubleVal
      } else if let boolVal = try? container.decode(Bool.self) {
        value = boolVal
      } else if let stringVal = try? container.decode(String.self) {
        value = stringVal
      } else {
        throw DecodingError.dataCorruptedError(in: container, debugDescription: "the container contains nothing serialisable")
      }
    } else {
      throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Could not serialise"))
    }
  }
}

Попробуйте использовать

let stud = try! JSONDecoder().decode(AnyDecodable.self, from: jsonData).value as! [String: Any]
print(stud)
Джузеппе Ланца
источник
6

Когда я нашел старый ответ, я протестировал только простой случай объекта JSON, но не пустой, который вызовет исключение времени выполнения, такое как @slurmomatic и @zoul found. Извините за эту проблему.

Поэтому я пробую другой способ, используя простой протокол JSONValue, реализую AnyJSONValueструктуру стирания типа и использую этот тип вместо Any. Вот реализация.

public protocol JSONType: Decodable {
    var jsonValue: Any { get }
}

extension Int: JSONType {
    public var jsonValue: Any { return self }
}
extension String: JSONType {
    public var jsonValue: Any { return self }
}
extension Double: JSONType {
    public var jsonValue: Any { return self }
}
extension Bool: JSONType {
    public var jsonValue: Any { return self }
}

public struct AnyJSONType: JSONType {
    public let jsonValue: Any

    public init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()

        if let intValue = try? container.decode(Int.self) {
            jsonValue = intValue
        } else if let stringValue = try? container.decode(String.self) {
            jsonValue = stringValue
        } else if let boolValue = try? container.decode(Bool.self) {
            jsonValue = boolValue
        } else if let doubleValue = try? container.decode(Double.self) {
            jsonValue = doubleValue
        } else if let doubleValue = try? container.decode(Array<AnyJSONType>.self) {
            jsonValue = doubleValue
        } else if let doubleValue = try? container.decode(Dictionary<String, AnyJSONType>.self) {
            jsonValue = doubleValue
        } else {
            throw DecodingError.typeMismatch(JSONType.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Unsupported JSON tyep"))
        }
    }
}

А вот как его использовать при декодировании

metadata = try container.decode ([String: AnyJSONValue].self, forKey: .metadata)

Проблема с этим вопросом в том, что мы должны позвонить value.jsonValue as? Int. Нам нужно дождаться Conditional Conformanceприземления в Swift, чтобы решить эту проблему или, по крайней мере, помочь ей стать лучше.


[Старый ответ]

Я размещаю этот вопрос на форуме разработчиков Apple, и оказалось, что это очень просто.

я могу сделать

metadata = try container.decode ([String: Any].self, forKey: .metadata)

в инициализаторе.

Во-первых, мне было плохо по этому поводу.

Питифонг Фонгпаттранонт
источник
4
Мог опубликовать ссылку на вопрос по Apple Developer. Anyне соответствует, Decodableпоэтому я не уверен, насколько это правильный ответ.
Реза
@RezaShirazian Это то, о чем я подумал в первую очередь. Но оказывается, что Dictionary соответствует Encodable, когда его ключи соответствуют Hashable и не зависят от его значений. Вы можете открыть заголовок словаря и убедиться в этом сами. extension Dictionary: Encodable where Key: Hashable extension Dictionary: Decodable where Key: Hashable Forums.developer.apple.com/thread/80288#237680
Pitiphong Phongpattranont,
6
в настоящее время это не работает. «Dictionary <String, Any> не соответствует Decodable, потому что Any не соответствует Decodable»
mbuchetics
Оказывается, это работает. Я использую это в своем коде. Вы должны понимать, что сейчас нет способа выразить требование, что «Значение словаря должно соответствовать протоколу Decodable, чтобы словарь соответствовал протоколу Decodable». Это «условное соответствие», которое еще не реализовано в Swift 4, я думаю, что на данный момент это нормально, поскольку в системе типов Swift (и универсальных шаблонах) существует множество ограничений. Так что сейчас это работает, но когда в будущем система типов Swift улучшится (особенно, когда будет реализовано условное соответствие), это не должно работать.
Pitiphong Phongpattranont
3
Не работает для меня с Xcode 9 beta 5. Компилируется, но срывается во время выполнения: Dictionary <String, Any> не соответствует Decodable, потому что Any не соответствует Decodable.
zoul
6

Если вы используете SwiftyJSON для анализа JSON, вы можете обновить его до версии 4.1.0, которая поддерживает Codableпротокол. Просто объявите, metadata: JSONи все готово.

import SwiftyJSON

struct Customer {
  let id: String
  let email: String
  let metadata: JSON
}
Аллен Хуанг
источник
Я не знаю, почему этот ответ был отклонен. Это полностью верно и решает проблему.
Леонид Усов
Кажется, это хорошо для перехода со SwiftyJSON на Decodable
Michał Ziobro
Это не решает, как затем анализировать метаданные json, что было исходной проблемой.
llamacorn
1

Вы можете взглянуть на BeyovaJSON

import BeyovaJSON

struct Customer: Codable {
  let id: String
  let email: String
  let metadata: JToken
}

//create a customer instance

customer.metadata = ["link_id": "linked-id","buy_count": 4]

let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted 
print(String(bytes: try! encoder.encode(customer), encoding: .utf8)!)
Каний
источник
Ох, действительно мило. Использование его для получения общего JSON как JToken, добавления некоторых значений и возврата на сервер. Действительно очень хорошо.
Отличная
1

Самый простой и рекомендуемый способ - создать отдельную модель для каждого словаря или модели в JSON .

Вот что я делаю

//Model for dictionary **Metadata**

struct Metadata: Codable {
    var link_id: String?
    var buy_count: Int?
}  

//Model for dictionary **Customer**

struct Customer: Codable {
   var object: String?
   var id: String?
   var email: String?
   var metadata: Metadata?
}

//Here is our decodable parser that decodes JSON into expected model

struct CustomerParser {
    var customer: Customer?
}

extension CustomerParser: Decodable {

//keys that matches exactly with JSON
enum CustomerKeys: String, CodingKey {
    case object = "object"
    case id = "id"
    case email = "email"
    case metadata = "metadata"
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CustomerKeys.self) // defining our (keyed) container

    let object: String = try container.decode(String.self, forKey: .object) // extracting the data
    let id: String = try container.decode(String.self, forKey: .id) // extracting the data
    let email: String = try container.decode(String.self, forKey: .email) // extracting the data

   //Here I have used metadata model instead of dictionary [String: Any]
    let metadata: Metadata = try container.decode(Metadata.self, forKey: .metadata) // extracting the data

    self.init(customer: Customer(object: object, id: id, email: email, metadata: metadata))

    }
}

Использование:

  if let url = Bundle.main.url(forResource: "customer-json-file", withExtension: "json") {
        do {
            let jsonData: Data =  try Data(contentsOf: url)
            let parser: CustomerParser = try JSONDecoder().decode(CustomerParser.self, from: jsonData)
            print(parser.customer ?? "null")

        } catch {

        }
    }

** Я использовал опцию optional, чтобы быть в безопасности при парсинге, при необходимости можно изменить.

Подробнее по этой теме

Минхазур
источник
1
Ваш ответ наверняка подходит для Swift 4.1, и первая строка вашего сообщения мертва! Предполагая, что данные поступают из веб-службы. вы можете моделировать простые вложенные объекты, а затем использовать точечный синтаксис для каждого из них. См. Ответ Сухита ниже.
Дэвид Х
1

Я сделал стручок , чтобы облегчить способ декодирования + кодирующий [String: Any], [Any]. И это обеспечивает кодирование или декодирование дополнительных свойств, здесь https://github.com/levantAJ/AnyCodable

pod 'DynamicCodable', '1.0'

Как это использовать:

import DynamicCodable

struct YourObject: Codable {
    var dict: [String: Any]
    var array: [Any]
    var optionalDict: [String: Any]?
    var optionalArray: [Any]?

    enum CodingKeys: String, CodingKey {
        case dict
        case array
        case optionalDict
        case optionalArray
    }

    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        dict = try values.decode([String: Any].self, forKey: .dict)
        array = try values.decode([Any].self, forKey: .array)
        optionalDict = try values.decodeIfPresent([String: Any].self, forKey: .optionalDict)
        optionalArray = try values.decodeIfPresent([Any].self, forKey: .optionalArray)
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(dict, forKey: .dict)
        try container.encode(array, forKey: .array)
        try container.encodeIfPresent(optionalDict, forKey: .optionalDict)
        try container.encodeIfPresent(optionalArray, forKey: .optionalArray)
    }
}
Тай Ле
источник
0

Вот более общий (не только [String: Any], но[Any] декодируемый) и инкапсулированный подход (для этого используется отдельный объект), вдохновленный ответом @loudmouth.

Использование будет выглядеть так:

extension Customer: Decodable {
  public init(from decoder: Decoder) throws {
    let selfContainer = try decoder.container(keyedBy: CodingKeys.self)
    id = try selfContainer.decode(.id)
    email = try selfContainer.decode(.email)
    let metadataContainer: JsonContainer = try selfContainer.decode(.metadata)
    guard let metadata = metadataContainer.value as? [String: Any] else {
      let context = DecodingError.Context(codingPath: [CodingKeys.metadata], debugDescription: "Expected '[String: Any]' for 'metadata' key")
      throw DecodingError.typeMismatch([String: Any].self, context)
    }
    self.metadata = metadata
  }

  private enum CodingKeys: String, CodingKey {
    case id, email, metadata
  }
}

JsonContainer- это вспомогательная сущность, которую мы используем для переноса декодирования данных JSON в объект JSON (массив или словарь) без расширения *DecodingContainer(поэтому он не будет мешать в редких случаях, когда объект JSON не подразумевается [String: Any]).

struct JsonContainer {

  let value: Any
}

extension JsonContainer: Decodable {

  public init(from decoder: Decoder) throws {
    if let keyedContainer = try? decoder.container(keyedBy: Key.self) {
      var dictionary = [String: Any]()
      for key in keyedContainer.allKeys {
        if let value = try? keyedContainer.decode(Bool.self, forKey: key) {
          // Wrapping numeric and boolean types in `NSNumber` is important, so `as? Int64` or `as? Float` casts will work
          dictionary[key.stringValue] = NSNumber(value: value)
        } else if let value = try? keyedContainer.decode(Int64.self, forKey: key) {
          dictionary[key.stringValue] = NSNumber(value: value)
        } else if let value = try? keyedContainer.decode(Double.self, forKey: key) {
          dictionary[key.stringValue] = NSNumber(value: value)
        } else if let value = try? keyedContainer.decode(String.self, forKey: key) {
          dictionary[key.stringValue] = value
        } else if (try? keyedContainer.decodeNil(forKey: key)) ?? false {
          // NOP
        } else if let value = try? keyedContainer.decode(JsonContainer.self, forKey: key) {
          dictionary[key.stringValue] = value.value
        } else {
          throw DecodingError.dataCorruptedError(forKey: key, in: keyedContainer, debugDescription: "Unexpected value for \(key.stringValue) key")
        }
      }
      value = dictionary
    } else if var unkeyedContainer = try? decoder.unkeyedContainer() {
      var array = [Any]()
      while !unkeyedContainer.isAtEnd {
        let container = try unkeyedContainer.decode(JsonContainer.self)
        array.append(container.value)
      }
      value = array
    } else if let singleValueContainer = try? decoder.singleValueContainer() {
      if let value = try? singleValueContainer.decode(Bool.self) {
        self.value = NSNumber(value: value)
      } else if let value = try? singleValueContainer.decode(Int64.self) {
        self.value = NSNumber(value: value)
      } else if let value = try? singleValueContainer.decode(Double.self) {
        self.value = NSNumber(value: value)
      } else if let value = try? singleValueContainer.decode(String.self) {
        self.value = value
      } else if singleValueContainer.decodeNil() {
        value = NSNull()
      } else {
        throw DecodingError.dataCorruptedError(in: singleValueContainer, debugDescription: "Unexpected value")
      }
    } else {
      let context = DecodingError.Context(codingPath: [], debugDescription: "Invalid data format for JSON")
      throw DecodingError.dataCorrupted(context)
    }
  }

  private struct Key: CodingKey {
    var stringValue: String

    init?(stringValue: String) {
      self.stringValue = stringValue
    }

    var intValue: Int?

    init?(intValue: Int) {
      self.init(stringValue: "\(intValue)")
      self.intValue = intValue
    }
  }
}

Обратите внимание, что числовые и логические типы поддерживаются NSNumber, иначе что-то вроде этого не сработает:

if customer.metadata["keyForInt"] as? Int64 { // as it always will be nil
Алексей Кожевников
источник
Могу ли я декодировать только выбранные свойства и оставить другие декодированные автоматически, поскольку у меня есть 15 свойств, которых достаточно для autoDecoding, и, возможно, 3, которым требуется некоторая пользовательская обработка декодирования?
Michał Ziobro
@ MichałZiobro Вы хотите, чтобы часть данных была декодирована в объект JSON, а часть декодирована в отдельные переменные экземпляра? Или вы просите написать инициализатор частичного декодирования только для части объекта (и он не имеет ничего общего с JSON-подобной структурой)? Насколько мне известно, ответ на первый вопрос - да, на второй - нет.
Алексей Кожевников
Я хотел бы иметь только некоторые свойства с индивидуальным декодированием, а остальные со стандартным декодированием по умолчанию
Michał Ziobro
@ MichałZiobro Если я вас правильно понимаю, это невозможно. В любом случае, ваш вопрос не имеет отношения к текущему вопросу SO и заслуживает отдельного рассмотрения.
Алексей Кожевников
0

декодировать с помощью декодера и ключей кодирования

public let dataToDecode: [String: AnyDecodable]

enum CodingKeys: CodingKey {
    case dataToDecode
}

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    self.dataToDecode = try container.decode(Dictionary<String, AnyDecodable>.self, forKey: .dataToDecode) 
}    
Ашим Дахал
источник
-1
extension ViewController {

    func swiftyJson(){
        let url = URL(string: "https://itunes.apple.com/search?term=jack+johnson")
        //let url = URL(string: "http://makani.bitstaging.in/api/business/businesses_list")

        Alamofire.request(url!, method: .get, parameters: nil).responseJSON { response in
            var arrayIndexes = [IndexPath]()
            switch(response.result) {
            case .success(_):

                let data = response.result.value as! [String : Any]

                if let responseData =  Mapper<DataModel>().map(JSON: data) {
                    if responseData.results!.count > 0{
                        self.arrayExploreStylistList = []
                    }
                    for i in 0..<responseData.results!.count{
                        arrayIndexes.append(IndexPath(row: self.arrayExploreStylistList.count + i, section: 0))
                    }
                    self.arrayExploreStylistList.append(contentsOf: responseData.results!)

                    print(arrayIndexes.count)

                }

                //                    if let arrNew = data["results"] as? [[String : Any]]{
                //                        let jobData = Mapper<DataModel>().mapArray(JSONArray: arrNew)
                //                        print(jobData)
                //                        self.datamodel = jobData
                //                    }
                self.tblView.reloadData()
                break

            case .failure(_):
                print(response.result.error as Any)
                break

            }
        }

    }
}
наемник
источник