Як розшифрувати властивість з типом словника JSON у протоколі декодування Swift 4


103

Скажімо, у мене є 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?

Відповіді:


89

З деяким натхненням від цієї суті, яку я знайшов, я написав деякі розширення для 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]]

EDIT 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 Остання умова в in 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.
чебур

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" . (Якщо "generic" означає "з попередньо невідомою структурою").

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

Ви маєте на увазі, що це може бути або тип масиву, або словник?
Suhit Patil

ви можете навести приклад або додати більше пояснень щодо структури метаданих
Suhit Patil

2
Значенням metadataможе бути будь-який об’єкт JSON. Так це може бути порожній словник або будь-який словник. "metadata": {} "metadata": {user_id: "id"} "metadata": {уподобання: {shows_value: true, language: "en"}} тощо
Pitiphong Phongpattranont

одним із можливих варіантів може бути використання всіх параметрів у структурі метаданих як додаткових параметрів та перерахування всіх можливих значень у структурі метаданих, таких як метадані структури {var user_id: String? var preference: String? }
Suhit Patil

8

Я прийшов із дещо іншим рішенням.

Припустимо, у нас є щось більше, ніж простий [String: 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висадимося у Свіфта, що вирішить цю проблему або хоча б допоможе їй стати кращим.


[Стара відповідь]

Я розміщую це питання на форумі Apple Developer, і виявляється, це дуже просто.

я можу зробити

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

в ініціалізаторі.

Мені було погано пропустити це в першу чергу.


4
Не вдалося опублікувати посилання на запитання в Apple Developer. Anyне відповідає Decodableтому я не впевнений, наскільки це правильна відповідь.
Реза Ширазіян

@RezaShirazian Саме це я подумав в першу чергу. Але виявляється, що словник відповідає Encodable, коли його ключі відповідають Hashable і не залежать від його значень. Ви можете відкрити заголовок словника і побачити це самостійно. Словник розширення: Encodable where Key: Словник розширення Hashable: Decodable where Key: Hashable forums.developer.apple.com/thread/80288#237680
Pitiphong Phongpattranont

6
на даний момент це не працює. "Словник <Рядок, Будь-який> не відповідає Decodable, оскільки будь-який не відповідає Decodable"
mbuchetics

Виявляється, це працює. Я використовую це у своєму коді. Вам потрібно зрозуміти, що немає можливості висловити вимогу, що "Значення Словника повинно відповідати протоколу декодируемости для того, щоб Словник відповідав протоколу Розширюваного". Це "Умовна відповідність", яка ще не реалізована в Swift 4. Я думаю, що зараз це нормально, оскільки в системі типів Swift (і в Generics) є багато обмежень. Отже, це працює на даний момент, але коли система типу Swift вдосконалиться в майбутньому (особливо, коли впроваджено умовне відповідність), це не повинно працювати.
Pitiphong Phongpattranont

3
Не працює для мене, як для Xcode 9 beta 5. Компілюється, але вибухає під час виконання: Словник <String, Any> не відповідає Decodable, оскільки будь-який не відповідає 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 на розшифровку
Michał

Це не вирішує, як потім розібрати метадані json, що було початковою проблемою.
ламакорн,

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 {

        }
    }

** Я використовував необов'язково, щоб бути в безпечній стороні під час розбору, можна змінювати за потребою.

Читайте докладніше на цю тему


1
Ваша відповідь точно відповідна Swift 4.1, і перший рядок вашої публікації вже мертвий! Припустимо, що дані надходять від веб-сервісу. ви можете моделювати прості вкладені об'єкти, а потім використовувати синтаксис крапок, щоб захопити кожен. Дивіться відповідь suhit нижче.
Девід Н

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 властивостей, яких вистачає для автоматичного декодування та, можливо, 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

            }
        }

    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.