Могу я просто добавить; люди всегда предполагают, что это компьютерная проблема, но если вы считаете своими руками (база 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 пальцами на каждой руке спросит, почему ваша десятичная математика была сломана ...
Для десериализации 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)
}
Я лично предпочитаю собственный парсинг против какой-либо третьей стороны, так как он прозрачен и без магии. (и ошибка меньше?)
Еще один обработчик 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
Используя 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"
}""")!
Этот способ позволяет пользователю получить 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
}
Если вам нужен синтаксический анализ и json без необходимости вручную сопоставлять ключи и поля, вы также можете использовать EVReflection . Затем вы можете использовать код типа:
var user:User = User(json:jsonString)
или
var jsonString:String = user.toJsonString()
Единственное, что вам нужно сделать, это использовать EVObject в качестве базового класса объектов данных. См. Страницу GitHub для более подробного примера кода
Недавно я написал небольшую библиотеку с открытым исходным кодом, которая позволяет быстро и легко десериализовать словари в объекты 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"]
}
}
Я расширяю превосходные ответы 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)")
}
Вы делаете это, используя 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 . Вы должны проверить учебник, поскольку он идет намного глубже и охватывает лучшую обработку ошибок.
Поскольку вы даете очень простой объект 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"
}
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"
Я рекомендую вам использовать генерацию кода ( http://www.json4swift.com ) для создания собственных моделей из json-ответа, это сэкономит ваше время на парсинг вручную и уменьшит риск ошибок из-за ошибочных ключей, все элементы будут доступны по свойствам модели, это будет чисто натуральным, и модели будут иметь больше смысла, чем проверка ключей.
Ваше преобразование будет таким же простым, как:
let userObject = UserClass(userDictionary)
print(userObject!.name)
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) }
В Swift 4 вы можете использовать протоколы декодирования, кодированияKey для десериализации ответа JSON:
class UserInfo: Decodable
var name: String
var email: String
var password: String
enum UserInfoCodingKey: String, CodingKey {
case name
case password
case emailId
}
required init(from decoder: Decoder) throws
Весь класс выглядит так: let userInfo = try JsonDecoder().decode(UserInfo.self, from: jsonData)