создавать экземпляры класса из json-массива [duplicate]

Могу я просто добавить; люди всегда предполагают, что это компьютерная проблема, но если вы считаете своими руками (база 10), вы не можете получить (1/3+1/3=2/3)=true, если у вас нет бесконечности, чтобы добавить 0.333 ... в 0.333 ... так, как и с (1/10+2/10)!==3/10 в базе 2, вы обрезаете ее до 0,333 + 0,333 = 0,666 и, вероятно, округлите ее до 0,677, что также будет технически неточным.

Подсчитайте в тройном, а третья не проблема, может быть, какая-то гонка с 15 пальцами на каждой руке спросит, почему ваша десятичная математика была сломана ...

48
задан Moritz 3 February 2016 в 23:33
поделиться

13 ответов

Для десериализации JSON с помощью Swift 2.0

есть отличный пример . Трюк состоит в том, чтобы использовать ключевое слово guard и цепочки присвоений следующим образом:

init?(attributes: [String : AnyObject]) {
    guard let name = attributes["name"] as? String,
        let coordinates = attributes["coordinates"] as? [String: Double],
        let latitude = coordinates["lat"],
        let longitude = coordinates["lng"],
        else {
            return nil
    }
    self.name = name
    self.coordinates = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}

Я лично предпочитаю собственный парсинг против какой-либо третьей стороны, так как он прозрачен и без магии. (и ошибка меньше?)

4
ответ дан AmitP 28 August 2018 в 08:26
поделиться

Еще один обработчик JSON я написал:

С ним вы можете сделать следующее:

let obj:[String:AnyObject] = [
    "array": [JSON.null, false, 0, "", [], [:]],
    "object":[
        "null":   JSON.null,
        "bool":   true,
        "int":    42,
        "double": 3.141592653589793,
        "string": "a α\t弾\n                  
7
ответ дан dankogai 28 August 2018 в 08:26
поделиться

Используя quicktype , я сгенерировал вашу модель и сериализационные помощники из вашего образца:

import Foundation

struct User: Codable {
    let name: String
    let email: String
    let password: String
}

extension User {
    static func from(json: String, using encoding: String.Encoding = .utf8) -> OtherUser? {
        guard let data = json.data(using: encoding) else { return nil }
        return OtherUser.from(data: data)
    }

    static func from(data: Data) -> OtherUser? {
        let decoder = JSONDecoder()
        return try? decoder.decode(OtherUser.self, from: data)
    }

    var jsonData: Data? {
        let encoder = JSONEncoder()
        return try? encoder.encode(self)
    }

    var jsonString: String? {
        guard let data = self.jsonData else { return nil }
        return String(data: data, encoding: .utf8)
    }
}

Затем проанализируйте значения User следующим образом:

let user = User.from(json: """{
  "name": "myUser", 
  "email": "user@example.com",
  "password": "passwordHash"
}""")!
2
ответ дан David Siegel 28 August 2018 в 08:26
поделиться

Этот способ позволяет пользователю получить URL-адрес. Он разбирает NSData в NSDictionary, а затем в NSObject.

let urlS = "http://api.localhost:3000/"

func getUser(username: Strung) -> User {
   var user = User()
   let url = NSURL(string: "\(urlS)\(username)")
   if let data = NSData(contentsOfURL: url!) {
     setKeysAndValues(user, dictionary: parseData(data))
   }
   return user
}

func setKeysAndValues (object : AnyObject, dictionary : NSDictionary)  -> AnyObject  {
    for (key, value) in dictionary {
        if let key = key  as? String, let value = value as? String {
            if (object.respondsToSelector(NSSelectorFromString(key))) {
                object.setValue(value, forKey: key)
            }
        }
    }
    return object
}

func parseData (data : NSData)  -> NSDictionary  {
    var error: NSError?
    return NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary
}
1
ответ дан Eduardo Irias 28 August 2018 в 08:26
поделиться

Если вам нужен синтаксический анализ и json без необходимости вручную сопоставлять ключи и поля, вы также можете использовать EVReflection . Затем вы можете использовать код типа:

var user:User = User(json:jsonString)

или

var jsonString:String = user.toJsonString()

Единственное, что вам нужно сделать, это использовать EVObject в качестве базового класса объектов данных. См. Страницу GitHub для более подробного примера кода

3
ответ дан Edwin Vermeer 28 August 2018 в 08:26
поделиться

Недавно я написал небольшую библиотеку с открытым исходным кодом, которая позволяет быстро и легко десериализовать словари в объекты Swift: https://github.com/isair/JSONHelper

Использование это, десериализация данных становится такой же простой, как это:

var myInstance = MyClass(data: jsonDictionary)

или

myInstance <-- jsonDictionary

И модели должны выглядеть только так:

struct SomeObjectType: Deserializable {
    var someProperty: Int?
    var someOtherProperty: AnotherObjectType?
    var yetAnotherProperty: [YetAnotherObjectType]?

    init(data: [String: AnyObject]) {
        someProperty <-- data["some_key"]
        someOtherProperty <-- data["some_other_key"]
        yetAnotherProperty <-- data["yet_another_key"]
    }
}

Что в вашем случае было бы:

struct Person: Deserializable {
    var name: String?
    var email: String?
    var password: String?

    init(data: [String: AnyObject]) {
        name <-- data["name"]
        email <-- data["email"]
        password <-- data["password"]
    }
}
3
ответ дан isair 28 August 2018 в 08:26
поделиться

Я расширяю превосходные ответы Mohacs и Peter Kreinz только для того, чтобы охватить массив подобных объектов, где каждый объект содержит смесь действительных типов данных JSON. Если данные JSON, которые один обрабатывает, представляют собой массив подобных объектов, содержащий смесь типов данных JSON, цикл do для разбора данных JSON становится таким.

// Array of parsed objects
var parsedObjects = [ParsedObject]()
do {
    let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as [Dictionary<String, AnyObject>]
    // Loop through objects
    for dict in json {
        // ParsedObject is a single instance of an object inside the JSON data
        // Its properties are a mixture of String, Int, Double and Bool
        let parsedObject = ParsedObject()
        // Loop through key/values in object parsed from JSON
        for (key, value) in json {
            // If property exists, set the value
            if (parsedObject.respondsToSelector(NSSelectorFromString(keyName))) {
                // setValue can handle AnyObject when assigning property value
                parsedObject.setValue(keyValue, forKey: keyName)
            }
        }
        parsedObjects.append(parsedObject)
    }
} catch let error as NSError {
    print("Failed to load: \(error.localizedDescription)")
}
2
ответ дан jkwuc89 28 August 2018 в 08:26
поделиться

Вы делаете это, используя NSJSONSerialization . Где данные - ваш JSON.

Сначала оберните его в оператор if, чтобы обеспечить некоторую способность к обработке ошибок

if let data = data,
 json = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? [String: AnyObject] {
// Do stuff
} else {
  // Do stuff
  print("No Data :/")
}

, а затем назначьте их:

let email = json["email"] as? String
let name = json["name"] as? String
let password = json["password"] as? String

Теперь, это покажет вам результат:

print("Found User iname: \(name) with email: \(email) and pass \(password)")

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

0
ответ дан MarkP 28 August 2018 в 08:26
поделиться

Обновление SWIFT 4


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

Ваш пользовательский объект

class Person : NSObject {
    var name : String = ""
    var email : String = ""
    var password : String = ""

    init(JSONString: String) {
        super.init()

        var error : NSError?
        let JSONData = JSONString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)

        let JSONDictionary: Dictionary = NSJSONSerialization.JSONObjectWithData(JSONData, options: nil, error: &error) as NSDictionary

        // Loop
        for (key, value) in JSONDictionary {
            let keyName = key as String
            let keyValue: String = value as String

            // If property exists
            if (self.respondsToSelector(NSSelectorFromString(keyName))) {
                self.setValue(keyValue, forKey: keyName)
            }
        }
        // Or you can do it with using 
        // self.setValuesForKeysWithDictionary(JSONDictionary)
        // instead of loop method above
    }
}

И так вы вызываете свой собственный класс с помощью строки JSON.

override func viewDidLoad() {
    super.viewDidLoad()
    let jsonString = "{ \"name\":\"myUser\", \"email\":\"user@example.com\", \"password\":\"passwordHash\" }"
    var aPerson : Person = Person(JSONString: jsonString)
    println(aPerson.name) // Output is "myUser"
}
54
ответ дан mohacs 28 August 2018 в 08:26
поделиться

Swift 2: Мне очень нравится предыдущий пост Mohacs! Чтобы сделать его более объектно-ориентированным, я написал соответствующие пользовательские классы Extension:

extension NSObject{       
    convenience init(jsonStr:String) {            
        self.init()

        if let jsonData = jsonStr.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
        {
            do {
                let json = try NSJSONSerialization.JSONObjectWithData(jsonData, options: []) as! [String: AnyObject]

                // Loop
                for (key, value) in json {
                    let keyName = key as String
                    let keyValue: String = value as! String

                    // If property exists
                    if (self.respondsToSelector(NSSelectorFromString(keyName))) {
                        self.setValue(keyValue, forKey: keyName)
                    }
                }

            } catch let error as NSError {
                print("Failed to load: \(error.localizedDescription)")
            }
        }
        else
        {
            print("json is of wrong format!")
        }
    }
}

:

class Person : NSObject {
       var name : String?
       var email : String?
       var password : String?
}

class Address : NSObject {
       var city : String?
       var zip : String?
}

, вызывая пользовательские классы со строкой JSON:

var jsonString = "{ \"name\":\"myUser\", \"email\":\"user@example.com\", \"password\":\"passwordHash\" }"
let aPerson = Person(jsonStr: jsonString)
print(aPerson.name!) // Output is "myUser"

jsonString = "{ \"city\":\"Berlin\", \"zip\":\"12345\" }"
let aAddress = Address(jsonStr: jsonString)
print(aAddress.city!) // Output is "Berlin"
9
ответ дан Peter Kreinz 28 August 2018 в 08:26
поделиться

Я рекомендую вам использовать генерацию кода ( http://www.json4swift.com ) для создания собственных моделей из json-ответа, это сэкономит ваше время на парсинг вручную и уменьшит риск ошибок из-за ошибочных ключей, все элементы будут доступны по свойствам модели, это будет чисто натуральным, и модели будут иметь больше смысла, чем проверка ключей.

Ваше преобразование будет таким же простым, как:

let userObject = UserClass(userDictionary)
print(userObject!.name)
9
ответ дан Syed Absar 28 August 2018 в 08:26
поделиться

HandyJSON - еще один вариант для работы с JSON для вас. https://github.com/alibaba/handyjson

Он отделяет JSON от объекта напрямую. Нет необходимости указывать отношение отображения, нет необходимости наследовать из NSObject. Просто определите свой чистый-быстрый класс / struct и десериальный JSON.

class Animal: HandyJSON {
    var name: String?
    var id: String?
    var num: Int?

    required init() {}
}

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

if let animal = JSONDeserializer.deserializeFrom(jsonString) {
    print(animal)
}
3
ответ дан xuyecan 28 August 2018 в 08:26
поделиться

В Swift 4 вы можете использовать протоколы декодирования, кодированияKey для десериализации ответа JSON:

  1. Создать класс, который подтверждает декодируемый протокол class UserInfo: Decodable
  2. Создать члены класса var name: String var email: String var password: String
  3. Создайте перемычку ключа JSON, которая наследует от CodingKey enum UserInfoCodingKey: String, CodingKey { case name case password case emailId }
  4. Реализация init required init(from decoder: Decoder) throws Весь класс выглядит так:
  5. Call Decoder // jsonData - это ответ JSON, и мы получаем объект userInfo let userInfo = try JsonDecoder().decode(UserInfo.self, from: jsonData)
2
ответ дан Yogesh Bharate 28 August 2018 в 08:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: