Has anyone been able to find a way to parse through JSON files in Swift 3? I have been able to get the data to return but I am unsuccessful when it comes to breaking the data down into specific fields. I would post sample code but I've gone through so many different methods unsuccessfully and haven't saved any. The basic format I want to parse through is something like this. Thanks in advance.
{
"Language": {
"Field":[
{
"Number":"976",
"Name":"Test"
},
{
"Number":"977",
"Name":"Test"
}
]
}
}
Have you tried JSONSerialization.jsonObject(with:options:)?
var jsonString = "{" +
"\"Language\": {" +
"\"Field\":[" +
"{" +
"\"Number\":\"976\"," +
"\"Name\":\"Test\"" +
"}," +
"{" +
"\"Number\":\"977\"," +
"\"Name\":\"Test\"" +
"}" +
"]" +
"}" +
"}"
var data = jsonString.data(using: .utf8)!
let json = try? JSONSerialization.jsonObject(with: data)
Swift sometimes produces some very odd syntax.
if let number = json?["Language"]??["Field"]??[0]?["Number"] as? String {
print(number)
}
Everything in the JSON object hierarchy ends up getting wrapped as an optional (ie. AnyObject?). Array<T> subscript returns a non-optional T. For this JSON, which is wrapped in an optional, array subscript returns Optional<AnyObject>. However, Dictionary<K, V> subscript returns an Optional<V>. For this JSON, subscript returns the very odd looking
Optional<Optional<AnyObject>> (ie. AnyObject??).
json is an Optional<AnyObject>.
json?["Language"] returns an Optional<Optional<AnyObject>>.
json?["Language"]??["Field"] returns an Optional<Optional<AnyObject>>.
json?["Language"]??["Field"]??[0] returns an Optional<AnyObject>.
json?["Language"]??["Field"]??[0]?["Number"] returns an Optional<Optional<AnyObject>>.
json?["Language"]??["Field"]??[0]?["Number"] as? String returns an Optional<String>.
The Optional<String> is then used by the if let syntax to product a String.
Final note: iterating the field array looks like this.
for field in json?["Language"]??["Field"] as? [AnyObject] ?? [] {
if let number = field["Number"] as? String {
print(number)
}
}
Swift 4 Update
Swift 4 makes this all much easier to deal with. Again we will start with your test data (""" makes this so much nicer).
let data = """
{
"Language": {
"Field":[
{
"Number":"976",
"Name":"Test"
},
{
"Number":"977",
"Name":"Test"
}
]
}
}
""".data(using: .utf8)!
Next we can define classes around the objects used in your JSON.
struct Object: Decodable {
let language: Language
enum CodingKeys: String, CodingKey { case language="Language" }
}
struct Language: Decodable {
let fields: [Field]
enum CodingKeys: String, CodingKey { case fields="Field" }
}
struct Field: Decodable {
let number: String
let name: String
enum CodingKeys: String, CodingKey { case number="Number"; case name="Name" }
}
The CodingKeys enum is how struct properties are mapped to JSON object member strings. This mapping is done automagically by Decodable.
Parsing the JSON now is simple.
let object = try! JSONDecoder().decode(Object.self, from: data)
print(object.language.fields[0].name)
for field in object.language.fields {
print(field.number)
}
In Xcode 8 and Swift 3 id now imports as Any rather than AnyObject
This means that JSONSerialization.jsonObject(with: data) returns Any. So you have to cast the json data to a specific type like [String:Any]. Same applies to the next fields down the json.
var jsonString = "{" +
"\"Language\": {" +
"\"Field\":[" +
"{" +
"\"Number\":\"976\"," +
"\"Name\":\"Test1\"" +
"}," +
"{" +
"\"Number\":\"977\"," +
"\"Name\":\"Test2\"" +
"}" +
"]" +
"}" +
"}"
var data = jsonString.data(using: .utf8)!
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any] {
let language = parsedData["Language"] as! [String:Any]
print(language)
let field = language["Field"] as! [[String:Any]]
let name = field[0]["Name"]!
print(name) // ==> Test1
}
In practice you would probably want some specific field buried in the json. Lets assume it's the Name field of the first element of Field array. You can use a chain of unwraps like this to safely access the field:
var data = jsonString.data(using: .utf8)!
if let json = try? JSONSerialization.jsonObject(with: data) as? [String:Any],
let language = json?["Language"] as? [String:Any],
let field = language["Field"] as? [[String:Any]],
let name = field[0]["Name"] as? String, field.count > 0 {
print(name) // ==> Test1
} else {
print("bad json - do some recovery")
}
Also you may want to check Apple's Swift Blog Working with JSON in Swift
Shoving JSON into a string manually is a pita. Why don't you just put the JSON into a file and read that in?
Swift 3:
let bundle = Bundle(for: type(of: self))
if let theURL = bundle.url(forResource: "response", withExtension: "json") {
do {
let data = try Data(contentsOf: theURL)
if let parsedData = try? JSONSerialization.jsonObject(with: data) as! [String:Any] {
grok(parsedData)
}
} catch {
print(error)
}
}
override func viewDidLoad() {
super.viewDidLoad()
let url=URL(string:"http://api.androidhive.info/contacts/")
do {
let allContactsData = try Data(contentsOf: url!)
let allContacts = try JSONSerialization.jsonObject(with: allContactsData, options: JSONSerialization.ReadingOptions.allowFragments) as! [String : AnyObject]
if let arrJSON = allContacts["contacts"] {
for index in 0...arrJSON.count-1 {
let aObject = arrJSON[index] as! [String : AnyObject]
names.append(aObject["name"] as! String)
contacts.append(aObject["email"] as! String)
}
}
print(names)
print(contacts)
self.tableView.reloadData()
}
catch {
}
}
JSON Parsing in swift 4 using Decodable Protocol :
I create a mocky file using your json object :
http://www.mocky.io/v2/5a280c282f0000f92c0635e6
Here is the code to parse the JSON :
Model Creation :
import UIKit
struct Item : Decodable {
// Properties must be the same name as specified in JSON , else it will return nil
var Number : String
var Name : String
}
struct Language : Decodable {
var Field : [Item]
}
struct Result : Decodable {
var Language : Language
}
You can use optional in the model if you are uncertain that something might be missing in JSON file.
This is the parsing Logic :
class ViewController: UIViewController {
let url = "http://www.mocky.io/v2/5a280c282f0000f92c0635e6"
private func parseJSON() {
guard let url = URL(string: url) else { return }
let session = URLSession.shared.dataTask(with: url) { (data, response, error) in
guard let data = data else { return }
guard let result = try? JSONDecoder().decode(Result.self, from: data) else { return }
print("\n\nResult : \(result)")
}
session.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
parseJSON()
}
}
The Print Output :
Result : Result(Language: JSON_Parsing.Language(Field: [JSON_Parsing.Item(Number: "976", Name: "Test"), JSON_Parsing.Item(Number: "977", Name: "Test")]))
This the github Project link. You can check.
JSON Parsing using Swift 4 in Simple WAY
let url = URL(string: "http://mobileappdevelop.co/TIPIT/webservice/get_my_groups?user_id=5")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
print(json)
let posts = json["Field"] as? [[String: Any]] ?? []
print(posts)
} catch let error as NSError {
print(error)
}
}).resume()
}
Use SwiftJson library. I think its very easy way to parse.
let count: Int? = json["Field"].array?.count
if let ct = count {
for index in 0...ct-1{
let number = json ["Field"][index]["number"].string
let name = json ["Field"][index]["name"].string
....
like this .
dict = {
message = "Login successfully.";
status = 1;
"user_details" = (
{
dob = "1900-11-18";
email = "rizwan#gmail.com";
gender = male;
name = Rizwan;
nickname = Shaikh;
"profile_pic" = "1483434421.jpeg";
"social_id" = "<null>";
"user_id" = 2;
}
);
}
We can parse above json in Swift 3 as
var dict2 = dict as! [String : Any]
print(dict);
let demoStr = dict2["message"] as! String
print(demoStr)
let demoArray = dict2["user_details"] as! [Any]
let demoDict = demoArray[0] as! [String:Any]
print(demoDict["dob"]!)
Related
I have a json response like this
{
"name":"test",
"params":{
"param1":"testA",
"param2":4055,
"param3":9593.34959,
"question":"is this is a test?",
"anything":"testing?",
"random":true
},
"price":103.3
}
My codable struct looks like this
struct:Codable {
var name:String
var params:[String:String]?
var price:Double
}
I have set params to optional because sometimes there are no params but a lot of times there are and codable has an issue because I don't know what types the values in the params dictionary are. I don't even know what the keys are sometimes. I just want to parse them as a dictionary of keys and values with values of type Bool, Int, Double, or String. so a dict like this
let params = ["paramA":1, "param2":"test", "param3":true]
or in the case of the above json this:
let params = ["param1":"testA", "param2":4055, "param3": 9593.34959, "question":"is this is a test?", "anything":"testing?", "random":true]
I am pretty sure I have to create a custom decoder but not exactly sure how to do it.
In your case it's easier to decode json manually like so:
public enum SerializationError: Error {
case wrongRootElement(String)
case missing(String)
case invalid(String, Any)
}
struct YourStruct {
var name:String
var params:[String: String]?
var price:Double
}
extension YourStruct {
public init(json: Any) throws {
guard let jsonDict = json as? [String: Any] else {
throw SerializationError.wrongRootElement("Expected json dictionary not \(json)")
}
guard let name = jsonDict["name"] as? String else {
throw SerializationError.missing("name")
}
let params = jsonDict["params"] as? [String: Any]
let paramsStrs = params?.reduce(into: [String: String]()) { (result, keyValue) in
result[keyValue.key] = String(describing: keyValue.value)
}
guard let price = jsonDict["price"] as? Double else {
throw SerializationError.missing("price")
}
self.init(name: name, params: paramsStrs, price: price)
}
}
let anyYourStruct = try? JSONSerialization.jsonObject(with: jsonData, options: [])
let yourStruct = try? YourStruct(json: anyYourStruct)
I am trying to parse my JSON data and append only those objects into array which meets specified condition. At the moment I have commented out code which fetch all objects from the API and add them into array. However, I would like to limit it so that it only appends objects with "wger.de" value for "license_author" key.
However I am getting error on line:
if eachExercise["license_author"] == "wger.de"
Binary operator '==' cannot be applied to operands of type 'Any?' and 'String'.
However I still wants to keep it as Any object because I would like to fetch both strings and integers data from my API.
This is the code for my parseData() function:
func parseData() {
fetchedExercise = []
let urlPath = "https://wger.de/api/v2/exercise/?format=json&language=2&status=2"
let url = URL(string: urlPath)!
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print("Error while parsing JSON")
}
else {
do {
if let data = data,
let fetchedData = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves) as? [String:Any],
let exercises = fetchedData["results"] as? [[String: Any]] {
// WORKING CODE
/*
for eachExercise in exercises
{
let name = eachExercise["name"] as! String
let description = eachExercise["description"] as! String
self.fetchedExercise.append(Exercise(name: name, description: description))
}
*/
// TESTING
for eachExercise in exercises {
if eachExercise["license_author"] == "wger.de" {
let name = eachExercise["name"] as! String
let description = eachExercise["description"] as! String
let id = eachExercise["id"] as! Int
self.fetchedExercise.append(Exercise(name: name, description: description))
}
}
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}
catch {
print("Error while parsing data.")
}
}
}
task.resume()
}
Use the where clause and optional downcast Any to String
for eachExercise in exercises where eachExercise["license_author"] as? String == "wger.de" { ...
You need cast it to String.
if eachExercise["license_author"] as? String == "wger.de" {
}
I have a JSON parsing issue with my Swift code below. The error I am getting says that my JSON output does not contain a key value.
My code:
Alamofire.request(url, method: .get, headers: headers).responseJSON { (response) -> Void in
let jsonValue = response.result.value as! NSDictionary
if let bpArray = jsonValue["value"] as? [NSDictionary]{
for results in bpArray {...}
Issue:
This conversion doesnt work: if let bpArray = jsonValue["value"] as? [NSDictionary]
My JSON Structure:
{
d: {
results: [
{
__metadata: {},
Key: "AFBWhULFHtKU4j4FhWCmKg==",
ParentKey: "AAAAAAAAAAAAAAAAAAAAAA==",
RootKey: "AFBWhULFHtKU4j4FhWCmKg==",
Partner: "MM-CARR-01",
Type: "2",
Description: "MM Demo Carrier Created for Single Stop / MA",
FrieghtOrder: {}
},
...
Assuming you want to access the results key so try like this:-
if let bpArray = jsonValue["results"] as? [String: AnyObject]{
//yourcode
}
Well your json structure haven't got any key named as value and that's why it's giving an error.
In order to get results array, you first need to get the object in which they are nested and for example 'g' in your case:
if let data = jsonValue["d"] as? [NSDictionary]{
if let resultsArray = data["results"] as? NSArray {
//your code
}
}
Please Use Swifty Json Pod And Try this code
pod 'SwiftyJSON'
In Your file where you get response
import SwiftyJSON
Then After Use This Code
switch response.result {
case .success(let JSON2):
print("Success with JSON: \(JSON2)")
// print("Request failed with error: \(response.response?.statusCode)")
if let response = JSON2 as? NSMutableDictionary
{
}
else if let response = JSON2 as? NSDictionary
{
if let data = response?.object(forKey: "d") as? NSDictionary
{
if let resultsArray = data?.object(forKey: "results") as? NSArray
{
}
}
}
else if JSON2 is NSArray
{
let swjson = JSON(response.result.value!)
print(swjson)
// callback(swjson,nil)
var myMutableDictionary = [AnyHashable: Any]()
myMutableDictionary["myArray"] = swjson
callback(myMutableDictionary as NSDictionary?,nil)
print("accc")
}
else if ((JSON2 as? String) != nil)
{
let userDic : [String : String] = ["quatid":JSON2 as! String]
print(userDic)
}
break
case .failure(let error):
print("Request failed with error: \(error)")
}
Remember it's better we not use NSArray & NSDictionary like things in SWIFT, SWIFT it self providing let, var keyword for various data type.
First you can create your model where you can save the data.
MyModel.swift
class MyModel: NSObject {
var ParentKey : Int?
init(jsonObject:[String:Any]) {
ParentKey = jsonObject["ParentKey"] as? String ?? ""
}
}
Viewcontroller.Swift
var myModel : [MyModel] = []
if let responseData = response["d"] as? [String:Any]{
if let dataObject = responseData["results"] as? [[String:Any]]{
self.myModel = dataObject.map({return MyModel(jsonObject: $0)})//for assigning data into model
}
}
As most people said, I was wrong with "value". Hussain's answer to using [String:AnyObject] Helped.
I am not sure if the below is neat to achieve, but it did the magic. App loaded as expected. Code expert below:
Solution:
if let bpData = jsonValue["d"] as? [String: AnyObject]{
for results in bpData {
let arrayInterim = results.value as? NSArray
for i in 0 ..< arrayInterim!.count {
I am trying to parse my json data in swift 3.0. I am using Alamofire 4.0+
Here is my json
{
"token":
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80",
"expires": 1504428378111,
"user":
[{"user_id":13,"user_first_name":"Himanshu","user_last_name":"Srivastava","full_name":"Himanshu Srivastava"}]
}
Here is my model class to hold these values
import Foundation
import ObjectMapper
class LoginResult:Mappable{
var token:String?
var expires:Double?
var users:[[String:Any]]?
required init?(map:Map){
}
func mapping(map:Map)->Void{
self.token <- map["token"]
self.expires <- map["expires"]
self.users <- map["user"]
}
}
None of the solution available on internet worked for me. How can I parse this json and map to the model class?
Any help here?
I was mistaken, the value for key user is indeed a regular array.
This is a solution without a third party mapper and with an extra User struct (by the way the value for key expires is an Int rather than Double).
Assuming the user data comes from a database which always sends all fields the user keys are forced unwrapped. If this is not the case use optional binding also for the user data:
struct User {
let firstName : String
let lastName : String
let fullName : String
let userID : Int
}
class LoginResult {
let token : String
let expires : Int
var users = [User]()
init(json : [String:Any]) {
self.token = json["token"] as? String ?? ""
self.expires = json["expires"] as? Int ?? 0
if let users = json["user"] as? [[String:Any]] {
self.users = users.map { User(firstName: $0["user_first_name"] as! String,
lastName: $0["user_last_name"] as! String,
fullName: $0["full_name"] as! String,
userID: $0["user_id"] as! Int)
}
}
}
}
let json = "{\"token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80\",\"expires\":504428378111,\"user\":[{\"user_id\":13,\"user_first_name\":\"Himanshu\",\"user_last_name\":\"Srivastava\",\"full_name\":\"Himanshu Srivastava\"}]}"
let jsonData = json.data(using: .utf8)!
do {
if let userData = try JSONSerialization.jsonObject(with: jsonData) as? [String:Any] {
let loginResult = LoginResult(json: userData)
print(loginResult.users[0])
// do something with loginResult
}
} catch {
print(error)
}
Here is the answer with map replaced by dictionary. Don't forget to handle error or unwrap carefully :)
let str = "{\"token\": \"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE1MDQ0MjgzNzgxMTF9.CNonyvtQbRgaqqkdPO5KwqpVaUmlGrpaTqlBxmvaX80\",\"expires\": 1504428378111,\"user\": [{\"user_id\":13,\"user_first_name\":\"Himanshu\",\"user_last_name\":\"Srivastava\",\"full_name\":\"Himanshu Srivastava\"}]}"
let data = str.data(using: .utf8)
do{
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
//Pass this json into the following function
}catch let error{
}
func mapping(json:[String: Any]?)->Void{
self.token <- json?["token"] as? String
self.expires <- json?["expires"] as? Double
self.users <- json?["user"] as? [[String: Any]]
}
I'm trying to parse a json but I have some difficulties with the data types and notably the AnyObject type + downcasting.
Let's consider the following json (it's an extract of a full json).
{ "weather":
[
{
"id":804,
"main":"Clouds",
"description":"overcast clouds",
"icon":"04d"
}
],
}
To me, the json can be described as follow :
- json: Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
- "weather": Array of type [AnyObject] (or NSArray)
- Dictionary of type [String: AnyObject] (or NSDictionary, so = [NSObject, AnyObject] in Xcode 6 b3)
My json is of type AnyObject! (I use JSONObjectWithData to get the JSON from a URL).
I then want to access the weather Dictionary. Here is the code I wrote.
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &localError)
if let dict = json as? [String: AnyObject] {
if let weatherDictionary = dict["weather"] as? [AnyObject] {
// Do stuff with the weatherDictionary
}
}
Here is the error I got
Playground execution failed: error: <EXPR>:28:56: error: '[AnyObject]' is not a subtype of '(String, AnyObject)'
if let weatherDictionary = dict["weather"] as? [AnyObject] {
I don't understand why dict["weather"] is compared to a subtype of (String, AnyObject) and not AnyObject.
I declared my dictionary as [String: AnyObject], so I i access a value using the String key, I should have an AnyObject, no ?
If I use NSDictionary instead of [String: AnyObject], it works.
If I use NSArray instead of [AnyObject], it works.
- The Xcode 6 beta 3 release notes tell that "NSDictionary* is now imported from Objective-C APIs as [NSObject : AnyObject].".
- And the Swift book: "When you bridge from an NSArray object to a Swift array, the resulting array is of type [AnyObject]."
EDIT
I forgot to force unwrapping the dict["weather"]!.
if let dict = json as? [String: AnyObject] {
println(dict)
if let weatherDictionary = dict["weather"]! as? [AnyObject] {
println("\nWeather dictionary:\n\n\(weatherDictionary)")
if let descriptionString = weatherDictionary[0]["description"]! as? String {
println("\nDescription of the weather is: \(descriptionString)")
}
}
}
Note that we should double check for the existence of the first Optional.
if let dict = json as? [String: AnyObject] {
for key in ["weather", "traffic"] {
if let dictValue = dict[key] {
if let subArray = dictValue as? [AnyObject] {
println(subArray[0])
}
} else {
println("Key '\(key)' not found")
}
}
}
This works fine for me in the playground and in the terminal using env xcrun swift
UPDATED FOR SWIFT 4 AND CODABLE
Here is a Swift 4 example using the Codable protocol.
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
struct Weather: Codable {
let id: Int
let main: String
let description: String
let icon: String
}
struct Result: Codable {
let weather: [Weather]
}
do {
let weather = try JSONDecoder().decode(Result.self, from: jsonStr.data(using: .utf8)!)
print(weather)
}
catch {
print(error)
}
UPDATED FOR SWIFT 3.0
I have updated the code for Swift 3 and also showed how to wrap the parsed JSON into objects. Thanks for all the up votes!
import Foundation
struct Weather {
let id: Int
let main: String
let description: String
let icon: String
}
extension Weather {
init?(json: [String: Any]) {
guard
let id = json["id"] as? Int,
let main = json["main"] as? String,
let description = json["description"] as? String,
let icon = json["icon"] as? String
else { return nil }
self.id = id
self.main = main
self.description = description
self.icon = icon
}
}
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
enum JSONParseError: Error {
case notADictionary
case missingWeatherObjects
}
var data = jsonStr.data(using: String.Encoding.ascii, allowLossyConversion: false)
do {
var json = try JSONSerialization.jsonObject(with: data!, options: [])
guard let dict = json as? [String: Any] else { throw JSONParseError.notADictionary }
guard let weatherJSON = dict["weather"] as? [[String: Any]] else { throw JSONParseError.missingWeatherObjects }
let weather = weatherJSON.flatMap(Weather.init)
print(weather)
}
catch {
print(error)
}
-- Previous Answer --
import Foundation
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
var localError: NSError?
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers, error: &localError)
if let dict = json as? [String: AnyObject] {
if let weather = dict["weather"] as? [AnyObject] {
for dict2 in weather {
let id = dict2["id"]
let main = dict2["main"]
let description = dict2["description"]
println(id)
println(main)
println(description)
}
}
}
Since I'm still getting up-votes for this answer, I figured I would revisit it for Swift 2.0:
import Foundation
var jsonStr = "{\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],}"
var data = jsonStr.dataUsingEncoding(NSASCIIStringEncoding, allowLossyConversion: false)
do {
var json = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
if let dict = json as? [String: AnyObject] {
if let weather = dict["weather"] as? [AnyObject] {
for dict2 in weather {
let id = dict2["id"] as? Int
let main = dict2["main"] as? String
let description = dict2["description"] as? String
print(id)
print(main)
print(description)
}
}
}
}
catch {
print(error)
}
The biggest difference is that the variable json is no longer an optional type and the do/try/catch syntax. I also went ahead and typed id, main, and description.
Try:
https://github.com/dankogai/swift-json
With it you can go like this:
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 // ""
Using my library (https://github.com/isair/JSONHelper) you can do this with your json variable of type AnyObject:
var weathers = [Weather]() // If deserialization fails, JSONHelper just keeps the old value in a non-optional variable. This lets you assign default values like this.
if let jsonDictionary = json as? JSONDictionary { // JSONDictionary is an alias for [String: AnyObject]
weathers <-- jsonDictionary["weather"]
}
Had your array not been under the key "weather", your code would have been just this:
var weathers = [Weather]()
weathers <-- json
Or if you have a json string in your hands you can just pass it as well, instead of creating a JSON dictionary from the string first. The only setup you need to do is writing a Weather class or struct:
struct Weather: Deserializable {
var id: String?
var name: String?
var description: String?
var icon: String?
init(data: [String: AnyObject]) {
id <-- data["id"]
name <-- data["name"]
description <-- data["description"]
icon <-- data["icon"]
}
}