将JSON/NSDictionary反序列化为Swift对象

dim*_*tri 52 json swift

有没有办法正确反序列化对Swift对象的JSON响应resp.使用DTO作为固定JSON API的容器?

类似于http://james.newtonking.com/json的东西或类似Java的这个例子

User user = jsonResponse.readEntity(User.class);
Run Code Online (Sandbox Code Playgroud)

jsonResponse.toString()就像这样的东西

{
  "name": "myUser", 
  "email": "user@example.com",
  "password": "passwordHash"
}
Run Code Online (Sandbox Code Playgroud)

moh*_*acs 60

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
    }
}
Run Code Online (Sandbox Code Playgroud)

这就是您使用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"
}
Run Code Online (Sandbox Code Playgroud)

  • 没有办法以"纯粹"的Swift方式从字符串"email"映射到email属性,因为没有内省.如果不使用KVO就不可能做到你要求的东西,因为你猜测KVO目前要求你依赖Objective-C. (3认同)

Sye*_*sar 10

我建议您使用代码生成(http://www.json4swift.com)从json响应中创建本机模型,这将节省您手动解析的时间,并降低因错误键导致错误的风险,所有元素可以通过模型属性访问,这将是纯粹的原生,模型将更有意义,而不是检查键.

您的转换将非常简单:

let userObject = UserClass(userDictionary)
print(userObject!.name)
Run Code Online (Sandbox Code Playgroud)


Pet*_*inz 9

斯威夫特2:我真的很喜欢上一篇莫哈奇的帖子!为了使它更面向对象,我写了一个匹配的扩展:

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!")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

自定义类:

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

class Address : NSObject {
       var city : String?
       var zip : String?
}
Run Code Online (Sandbox Code Playgroud)

使用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"
Run Code Online (Sandbox Code Playgroud)


dan*_*gai 7

我写的另一个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           // ""
Run Code Online (Sandbox Code Playgroud)

如您所见!?,下标之间不需要.

除此之外,您可以像这样应用自己的架构:

//// 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?
Run Code Online (Sandbox Code Playgroud)


Ami*_*itP 5

Apple有一个很好的例子,使用 Swift 2.0 反序列化 JSON

诀窍是使用 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)
}
Run Code Online (Sandbox Code Playgroud)

与任何第三方相比,我个人更喜欢本机解析,因为它是透明且无魔法的。(并且 bug 更少?)