Подтвердить что ты не робот

Сопоставление объекта JSON с классом/структурой Swift

Мне нужно "реплицировать" entiry, который возвращается из службы удаленного веб-API в JSON. Это выглядит так:

{
  "field1": "some_id",
  "entity_name" = "Entity1"
  "field2": "some name",
  "details1": [{
    "field1": 11,
    "field2": "some value",
    "data": {
      "key1": "value1",
      "key2": "value2",
      "key3": "value3",
      // any other, unknown at compile time keys
    }
  }],
  "details2": {
    "field1": 13,
    "field2": "some value2"
  }
}

Здесь моя попытка:

struct Entity1 {
  struct Details1 {
    let field1: UInt32
    let field2: String
    let data: [String: String]
  }

  struct Details2 {
    let field1: UInt32
    let field2: String
  }

  let field1: String
  static let entityName = "Entity1"
  let field2: String
  let details1: [Details1]
  let details2: Details2 
}
  • Это хорошая идея использовать структуры вместо классов для такой цели Как мой?
  • Можно ли каким-либо образом определить вложенную структуру или класс, скажем, Details1 и создать переменную в одно и то же время?

Вот так:

//doesn't compile 
struct Entity1 {
  let details1: [Details1 { 
  let field1: UInt32
  let field2: String
  let data: [String: String]
}]
4b9b3361

Ответ 1

Вы можете использовать любые, если доступны следующие хорошие библиотеки с открытым исходным кодом для обработки сопоставления JSON с объектом в Swift, посмотрите:

У каждого есть хороший хороший учебник для начинающих.

Что касается темы struct или class, вы можете рассмотреть следующий текст из The Swift Programming Language:

Строковые экземпляры всегда передаются по значению, а класс экземпляры всегда передаются по ссылке. Это означает, что они подходит для различных задач. Поскольку вы считаете данные конструкции и функциональные возможности, необходимые для проекта, должна ли каждая конструкция данных быть определена как класс или как структура.

В качестве общего руководства рассмотрите вопрос о создании структуры, когда один или несколько из этих условий:

  • Основной целью структур является инкапсуляция нескольких относительно простых значений данных.
  • Разумно ожидать, что инкапсулированные значения будут скопированы, а не будут указаны, когда вы назначаете или передаете экземпляр этой структуры.
  • Любые свойства, хранящиеся в структуре, сами являются типами значений, которые также следует скопировать, а не ссылаться.
  • Структуре не нужно наследовать свойства или поведение другого существующего типа.

Примеры хороших кандидатов для структур включают:

  • Размер геометрической формы, возможно, инкапсулирует свойство width и свойство height, оба типа Double.
  • Способ ссылаться на диапазоны внутри серии, возможно, инкапсулируя свойство start и свойство length, как типа Int.
  • Точка в трехмерной системе координат, возможно, инкапсулирующая свойства x, y и z, каждый из которых является двойным.

Во всех остальных случаях определите класс и создайте экземпляры этого класса для управления и передачи по ссылке. На практике это означает, что большинство пользовательских конструктов данных должны быть классами, а не структурами.

Надеюсь, это поможет вам.

Ответ 2

HandyJSON - именно то, что вам нужно. См. Пример кода:

struct Animal: HandyJSON {
    var name: String?
    var id: String?
    var num: Int?
}

let jsonString = "{\"name\":\"cat\",\"id\":\"12345\",\"num\":180}"

if let animal = JSONDeserializer.deserializeFrom(json: jsonString) {
    print(animal)
}

https://github.com/alibaba/handyjson

Ответ 3

подробности

  • Xcode 10.2.1 (10E1001), Swift 5

связи

Бобы:

Больше информации:

задача

Получите результаты поиска itunes с помощью iTunes Search API с помощью простого запроса https://itunes.apple.com/search?term=jack+johnson

Полный образец

import UIKit
import Alamofire

// Itunce api doc: https://affiliate.itunes.apple.com/resources/documentation/itunes-store-web-service-search-api/#searching

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        loadData()
    }

    private func loadData() {
        let urlString = "https://itunes.apple.com/search?term=jack+johnson"
        Alamofire.request(urlString).response { response in
            guard let data = response.data else { return }
            do {
                let decoder = JSONDecoder()
                decoder.keyDecodingStrategy = .convertFromSnakeCase
                let result = try decoder.decode(ItunceItems.self, from: data)
                print(result)
            } catch let error {
                print("\(error.localizedDescription)")
            }
        }
    }
}

struct ItunceItems: Codable {
    let resultCount: Int
    let results: [ItunceItem]
}

struct ItunceItem: Codable {
    var wrapperType: String?
    var artistId: Int?
    var trackName: String?
    var trackPrice: Double?
    var currency: String?
}

Ответ 4

вы можете использовать SwiftyJson и let json = JSONValue(dataFromNetworking) if let userName = json[0]["user"]["name"].string{ //Now you got your value }

Ответ 5

Взгляните на эту удивительную библиотеку, которая идеально подходит вам, Argo on GitHub.

В вашем случае структура в порядке. Вы можете узнать больше о том, как выбрать между структурой и классом здесь.

Ответ 6

Вы можете пойти с этим расширением для Alamofire https://github.com/sua8051/AlamofireMapper

Объявите класс или структуру:

class UserResponse: Decodable {
    var page: Int!
    var per_page: Int!
    var total: Int!
    var total_pages: Int!

    var data: [User]?
}

class User: Decodable {
    var id: Double!
    var first_name: String!
    var last_name: String!
    var avatar: String!
}

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

import Alamofire
import AlamofireMapper

let url1 = "https://raw.githubusercontent.com/sua8051/AlamofireMapper/master/user1.json"
        Alamofire.request(url1, method: .get
            , parameters: nil, encoding: URLEncoding.default, headers: nil).responseObject { (response: DataResponse<UserResponse>) in
                switch response.result {
                case let .success(data):
                    dump(data)
                case let .failure(error):
                    dump(error)
                }
        }