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

Уничтожить объекты JSON/NSDictionary для Swift

Есть ли способ правильно десериализовать ответ JSON для объектов Swift соответственно. используя DTO в качестве контейнеров для фиксированных API-интерфейсов JSON?

Что-то похожее на http://james.newtonking.com/json или что-то вроде этого примера с Java

User user = jsonResponse.readEntity(User.class);

в результате чего jsonResponse.toString() является чем-то вроде

{
  "name": "myUser", 
  "email": "[email protected]",
  "password": "passwordHash"
}
4b9b3361

Ответ 1

Обновление 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\":\"[email protected]\", \"password\":\"passwordHash\" }"
    var aPerson : Person = Person(JSONString: jsonString)
    println(aPerson.name) // Output is "myUser"
}

Ответ 2

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

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\":\"[email protected]\", \"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"

Ответ 3

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

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

let userObject = UserClass(userDictionary)
print(userObject!.name)

Ответ 4

Еще один обработчик 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𪚲",
        "array":  [],
        "object": [:]
    ],
    "url":"http://blog.livedoor.com/dankogai/"
]

let json = JSON(obj)

json.toString()
json["object"]["null"].asNull       // NSNull()
json["object"]["bool"].asBool       // true
json["object"]["int"].asInt         // 42
json["object"]["double"].asDouble   // 3.141592653589793
json["object"]["string"].asString   // "a α\t弾\n𪚲"
json["array"][0].asNull             // NSNull()
json["array"][1].asBool             // false
json["array"][2].asInt              // 0
json["array"][3].asString           // ""

Поскольку вы не видите !? между индексами.

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

//// schema by subclassing
class MyJSON : JSON {
    override init(_ obj:AnyObject){ super.init(obj) }
    override init(_ json:JSON)  { super.init(json) }
    var null  :NSNull? { return self["null"].asNull }
    var bool  :Bool?   { return self["bool"].asBool }
    var int   :Int?    { return self["int"].asInt }
    var double:Double? { return self["double"].asDouble }
    var string:String? { return self["string"].asString }
    var url:   String? { return self["url"].asString }
    var array :MyJSON  { return MyJSON(self["array"])  }
    var object:MyJSON  { return MyJSON(self["object"]) }
}

let myjson = MyJSON(obj)
myjson.object.null      // NSNull?
myjson.object.bool      // Bool?
myjson.object.int       // Int?
myjson.object.double    // Double?
myjson.object.string    // String?
myjson.url              // String?

Ответ 5

Недавно я написал небольшую библиотеку с открытым исходным кодом, которая позволяет быстро и легко десериализовать словари в объекты 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"]
    }
}

Ответ 6

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

var user:User = User(json:jsonString)

или

var jsonString:String = user.toJsonString()

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

Ответ 7

Там есть отличный пример от Apple для десериализации 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)
}

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

Ответ 8

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

Это deserials 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)
}

Ответ 9

Я расширяю на 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)")
}

Ответ 10

Используя 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": "[email protected]",
  "password": "passwordHash"
}""")!

Ответ 11

Этот способ позволяет пользователю получить 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
}

Ответ 12

Вы делаете это, используя 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. Вы должны проверить учебник, поскольку он идет намного глубже и охватывает лучшую обработку ошибок.

Ответ 13

Использовать мой пользовательский AGObject

Создайте модель с классом ужина AGObject

class Root: AGObject {
    ......
}

Назначить значение модели

Инициировать с помощью метода модели.

let root: Root = Root(with: yourDictObject)
print(root.toDict())

Прямое присвоение значения как.

root <= jsonResult
print(root.toDict())

Используя метод

root.assign(with: jsonResult)
print(root.toDict())

Json to Model Convert

var root = jsonResult.convert(Root.self)
print(root.toDict())