I'm trying to parse Json Data from an API :
{
"title": "Mr. Robot",
"first_aired": "2015-06-24",
"network": "USA Network",
"channels": [
{
"id": 12,
"name": "USA",
"short_name": "usa",
"channel_type": "television"
}
],
The Code I'm use is:
var TVArray : [TVInfo] = []
var task : NSURLSessionTask?
func getJSON (urlString: String) {
let url = NSURL(string: urlString)!
let session = NSURLSession.sharedSession()
task = session.dataTaskWithURL(url) {(data, response, error) in
dispatch_async(dispatch_get_main_queue()) {
if (error == nil) {
self.updateJSON(data)
}
else {
}
}
}
task!.resume()
}
func updateJSON (data: NSData!) {
let JSONData = (try! NSJSONSerialization.JSONObjectWithData(data, options: []))
TVArray.removeAll(keepCapacity: true)
if let jsonArray = JSONData {
for j in jsonArray {
let title = jsonResult["title"] as! String
let firstAired = jsonResult["first_aired"] as! String
let network = jsonResult["network"] as! String
let channelName = JsonResult["channels"][0]["name"] as! String
let TV = TVInfo(title: title, firstAired: firstAired, network: network, channelName: channelName)
TVArray.append(TV)
}
}
collectionview.reloadData()
}
}
When I use the above code I get an error 'Initializer for conditional binding must have Optional type, not 'AnyObject'' in front of the line 'if let jsonArray = JsonData'. I've tried some methods I've seen on StackOverflow like the method in the link :
[Parsing JSON in swift 2.0
but it didn't work for me. I'm still a bit new to Swift, I really don't want to use SwiftyJSON. Is this the best way to parse this JSON data or is there a better way of doing it?
Since you've used NSJSONSerialization with try! (note the !, meaning it was forced) the value of JSONData is not an optional: you don't have to unwrap it with if let jsonArray = JSONData.
If you still want an optional value, use try? instead.
Otherwise you could also use try inside a do catch block to handle possible errors.
The type of JSONData is unknown, it needs to be known to be an Array for the following for loop.
use:
let JSONData = try! NSJSONSerialization.JSONObjectWithData(data!, options:[]) as! NSArray
You do not need:
if let jsonArray = JSONData {
because you have already crashed if JSONData is nil from the preceding try!
You are better with:
do {
let jsonArray = try NSJSONSerialization.JSONObjectWithData(data!, options:[]) as! NSArray
for j in jsonArray {
// ...
}
} catch {
// handle error
}
Because you have no control over the JSON you receive and crashing because of a server change is not a good idea.
Also really put some time into naming variables, JSONData is not data, it is an array obtained by parsing a JSON string.
Related
I am brand new to writing swift so any tips on improvement/best practices are welcome but my main issue is that I am having trouble accessing a nested JSON array list. I am using this free API and trying to show a list of characters https://swapi.dev/api/people/
Please see the code snippet below.
When I print the type its : Optional<Any> and when i print json["results"] it prints the array like:
Optional(<__NSArrayI 0x600000fe31e0>(
{
"birth_year" = 19BBY;
created = "2014-12-09T13:50:51.644000Z";
....
I have tried several different things but have been unsuccessful. Could someone please give some advice on how I might iterate the list under json["results"?
func onLoad() -> Void {
let url = URL(string: "https://swapi.dev/api/people")
guard let requestUrl = url else { fatalError() }
// Create URL Request
var request = URLRequest(url: requestUrl)
// Specify HTTP Method to use
request.httpMethod = "GET"
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a simple String
if let data = data {
// let json = try? JSONSerialization.jsonObject(with: data, options: [])
do {
if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] {
// try to read out a string array
print(type(of: json["results"]))
print(json["results"])
}
} catch let error as Error {
print("Failed to load: \(error.localizedDescription)")
}
}
}
task.resume()
}
Thanks for any help!
You should really be using Decodable rather than trying to parse it with JSON as that can easily lead to errors as you are accessing values by strings and it doesn't allow the IDE to help you.
You need to create some objects that describe what you are getting in your response.
Your main json response is made up of the following
{
"count": 82,
"next": "http://swapi.dev/api/people/?page=2",
"previous": null,
"results": [...]
}
This allows you to create a People struct that conforms to Decodable.
struct People: Decodable {
let count: Int
let next: URL?
let previous: URL?
let results: [Person]
}
The results array is really what you are after as that contains all the information about a person.
{
"name": "Luke Skywalker",
"height": "172",
"mass": "77",
"hair_color": "blond",
"skin_color": "fair",
"eye_color": "blue",
"birth_year": "19BBY",
"gender": "male",
"homeworld": "http://swapi.dev/api/planets/1/",
"films": [
"http://swapi.dev/api/films/1/",
"http://swapi.dev/api/films/2/",
"http://swapi.dev/api/films/3/",
"http://swapi.dev/api/films/6/"
],
"species": [],
"vehicles": [
"http://swapi.dev/api/vehicles/14/",
"http://swapi.dev/api/vehicles/30/"
],
"starships": [
"http://swapi.dev/api/starships/12/",
"http://swapi.dev/api/starships/22/"
],
"created": "2014-12-09T13:50:51.644000Z",
"edited": "2014-12-20T21:17:56.891000Z",
"url": "http://swapi.dev/api/people/1/"
}
We can represent this with the following struct called Person that also conforms to Decodable
struct Person: Decodable {
let name: String
let height: String
let mass: String
let hairColor: String
let skinColor: String
let birthYear: String
let gender: Gender
let homeworld: String
let films: [URL]
let species: [URL]
let vehicles: [URL]
let starships: [URL]
let created: Date
let edited: Date
let url: URL
}
enum Gender: String, Decodable {
case male
case female
case unknown = "n/a"
}
Note a couple of differences between the names in the struct and the names in the object that you are getting back. eg hair_color (snakecase) and hairColor (camelCase) In Swift it is common to write it the latter way and when we use decodable we can tell our decoder to use a custom key decoding strategy. Also note that I have used an enum for Gender. This isn't required and we could have just used a String. Also note that created and edited are Dates, however they are not iso8601 compliant but we can also specify a custom date decoding strategy.
Here is how we can decode the data that you have received.
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let people = try decoder.decode(People.self, from: data)
Now we can put this all together in your network request to get the following:
func onLoad() {
let url = URL(string: "https://swapi.dev/api/people")
guard let requestUrl = url else { fatalError() }
// Create URL Request
var request = URLRequest(url: requestUrl)
// Specify HTTP Method to use
request.httpMethod = "GET"
// Send HTTP Request
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
// Check if Error took place
if let error = error {
print("Error took place \(error)")
return
}
// Convert HTTP Response Data to a simple String
if let data = data {
do {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'"
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let people = try decoder.decode(People.self, from: data)
people.results.forEach { person in print(person) }
} catch {
print("Failed to load: \(error)")
}
}
}
task.resume()
}
Cast results as an Array of Dictionary. Here's how
if let data = data {
do {
if let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
let results = json["results"] as? [[String: Any]] {
for result in results {
print(result)
}
}
} catch {
print("Failed to load: \(error.localizedDescription)")
}
}
Better Approach: Use Codable, JSONSerialization feels bit outdated.
Related Links:
https://developer.apple.com/documentation/swift/codable
https://www.swiftbysundell.com/basics/codable/
I wanted to know the best way to parse json response of below type in Swift 4. Response is double encoded -
\"[{\\"value\\":\\"International University \\\\"MITSO\\\\"\\",\\"id\\":\\"a1v24000000uOrPAAU\\",\\"addlFields\\":[\\"Mi?narodny Universitet \\\\"MITSO\\\\"\\"]}]\"
Here is the data in NSData format -
(String) $R0 = "data: Optional(146 bytes) as NSData: <225b7b5c 2276616c 75655c22 3a5c2249 6e746572 6e617469 6f6e616c 20556e69 76657273 69747920 5c5c5c22 4d495453 4f5c5c5c 225c222c 5c226964 5c223a5c 22613176 32343030 30303030 754f7250 4141555c 222c5c22 6164646c 4669656c 64735c22 3a5b5c22 4d693f6e 61726f64 6e792055 6e697665 72736974 6574205c 5c5c224d 4954534f 5c5c5c22 5c225d7d 5d22>"
As you see value of the key "value" has a inner double quotes(").
JSONSerialization consider this as invalid Json.
Any help will be greatly appreciated.
The content of your data as String is as follows:
"[{\"value\":\"International University \\\"MITSO\\\"\",\"id\":\"a1v24000000uOrPAAU\",\"addlFields\":[\"Mi?narodny Universitet \\\"MITSO\\\"\"]}]"
Seeing the actual content without extra double-quotes and backslashes needed to show String as String-literal, it looks like some valid JSON is embedded in a String.
This may happen when the server side code double-encodes the data. You should better tell your server side engineer to fix the issue, but if it is difficult or would take long time, you can double-decode it.
Testing code:
import Foundation
let dataStr = "<225b7b5c 2276616c 75655c22 3a5c2249 6e746572 6e617469 6f6e616c 20556e69 76657273 69747920 5c5c5c22 4d495453 4f5c5c5c 225c222c 5c226964 5c223a5c 22613176 32343030 30303030 754f7250 4141555c 222c5c22 6164646c 4669656c 64735c22 3a5b5c22 4d693f6e 61726f64 6e792055 6e697665 72736974 6574205c 5c5c224d 4954534f 5c5c5c22 5c225d7d 5d22>".dropFirst().dropLast().replacingOccurrences(of: " ", with: "")
let byteArr = stride(from: 0, to: dataStr.count, by: 2).map{(index: Int)->UInt8 in
let start = dataStr.index(dataStr.startIndex, offsetBy: index)
let end = dataStr.index(start, offsetBy: 2)
return UInt8(dataStr[start..<end], radix: 16)!
}
let responseData = Data(bytes: byteArr)
print(responseData as NSData)
Check here, whether the print statement output is exactly the same as your sample response. (If you want to test the following code with your actual data than sample response, use just let responseData = result as! Data instead of above lines.)
So, you just need to use JSONSerialization twice:
block: do {
let firstDecoded = try JSONSerialization.jsonObject(with: responseData, options: .allowFragments) as! String
let firstDecodedData = firstDecoded.data(using: .utf8)!
let secondDecoded = try JSONSerialization.jsonObject(with: firstDecodedData)
//Code below is an example of using decoded result.
guard let resultArray = secondDecoded as? [[String: Any]] else {
print("result is not an Array of Dictionary")
break block
}
print(resultArray)
if
let addlFields = resultArray[0]["addlFields"] as? [String],
let firstAddl = addlFields.first
{
print(firstAddl)
}
} catch {
print(error)
}
Outputs: (Omitting some output for print(responseData as NSData).)
[["id": a1v24000000uOrPAAU, "value": International University "MITSO", "addlFields": <__NSSingleObjectArrayI 0x100e40c80>(
Mi?narodny Universitet "MITSO"
)
]]
Mi?narodny Universitet "MITSO"
(You may find some parts like <__NSSingleObjectArrayI 0x100e40c80> are strange, but it's just a problem of generating default description and you can access the elements as an Array.)
Anyway, please try and see what you can get with my code above.
#OOPer thank you for the solution. Appreciate you giving your time.
Solution worked as expected. Pasting code here which may help others.
Here is how I am doing -
func getData(text:String, callback:#escaping (_ result: Array<somedata>?,_ error:Error?) -> Void) {
let params = ["search":text]
getDataSomeAPI(url: "http:\\xyz.com\fdf", params: params) { (result, error) in
if error == nil {
do {
//Response is double encoded
if let firstDecoded = try JSONSerialization.jsonObject(with: result as! Data, options: .allowFragments) as? String
{
let firstDecodedData = firstDecoded.data(using: .utf8)!
if let secondDecoded = try JSONSerialization.jsonObject(with: firstDecodedData) as? NSArray {
var array = [somedata]()
for obj in secondDecoded {
Mapper<somedata>().map(JSONObject: obj).then { mappedObj in
array.append(mappedObj)
}
}
callback(array,nil)
}
}
}
catch {
//Handle unexpected data format
let error = NSError(domain: "",
code: 0,
userInfo: nil)
let sErr = Error(err: error)
callback(nil, sErr)
}
} else {
callback(nil, error)
}
}
}
How do you convert an array to a JSON string in swift?
Basically I have a textfield with a button embedded in it.
When button is pressed, the textfield text is added unto the testArray.
Furthermore, I want to convert this array to a JSON string.
This is what I have tried:
func addButtonPressed() {
if goalsTextField.text == "" {
// Do nothing
} else {
testArray.append(goalsTextField.text)
goalsTableView.reloadData()
saveDatatoDictionary()
}
}
func saveDatatoDictionary() {
data = NSKeyedArchiver.archivedDataWithRootObject(testArray)
newData = NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions(), error: nil) as? NSData
string = NSString(data: newData!, encoding: NSUTF8StringEncoding)
println(string)
}
I would also like to return the JSON string using my savetoDictionart() method.
As it stands you're converting it to data, then attempting to convert the data to to an object as JSON (which fails, it's not JSON) and converting that to a string, basically you have a bunch of meaningless transformations.
As long as the array contains only JSON encodable values (string, number, dictionary, array, nil) you can just use NSJSONSerialization to do it.
Instead just do the array->data->string parts:
Swift 3/4
let array = [ "one", "two" ]
func json(from object:Any) -> String? {
guard let data = try? JSONSerialization.data(withJSONObject: object, options: []) else {
return nil
}
return String(data: data, encoding: String.Encoding.utf8)
}
print("\(json(from:array as Any))")
Original Answer
let array = [ "one", "two" ]
let data = NSJSONSerialization.dataWithJSONObject(array, options: nil, error: nil)
let string = NSString(data: data!, encoding: NSUTF8StringEncoding)
although you should probably not use forced unwrapping, it gives you the right starting point.
Swift 3.0 - 4.0 version
do {
//Convert to Data
let jsonData = try JSONSerialization.data(withJSONObject: dictionaryOrArray, options: JSONSerialization.WritingOptions.prettyPrinted)
//Convert back to string. Usually only do this for debugging
if let JSONString = String(data: jsonData, encoding: String.Encoding.utf8) {
print(JSONString)
}
//In production, you usually want to try and cast as the root data structure. Here we are casting as a dictionary. If the root object is an array cast as [Any].
var json = try JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
} catch {
print(error.description)
}
The JSONSerialization.WritingOptions.prettyPrinted option gives it to the eventual consumer in an easier to read format if they were to print it out in the debugger.
Reference: Apple Documentation
The JSONSerialization.ReadingOptions.mutableContainers option lets you mutate the returned array's and/or dictionaries.
Reference for all ReadingOptions: Apple Documentation
NOTE: Swift 4 has the ability to encode and decode your objects using a new protocol. Here is Apples Documentation, and a quick tutorial for a starting example.
If you're already using SwiftyJSON:
https://github.com/SwiftyJSON/SwiftyJSON
You can do this:
// this works with dictionaries too
let paramsDictionary = [
"title": "foo",
"description": "bar"
]
let paramsArray = [ "one", "two" ]
let paramsJSON = JSON(paramsArray)
let paramsString = paramsJSON.rawString(encoding: NSUTF8StringEncoding, options: nil)
SWIFT 3 UPDATE
let paramsJSON = JSON(paramsArray)
let paramsString = paramsJSON.rawString(String.Encoding.utf8, options: JSONSerialization.WritingOptions.prettyPrinted)!
JSON strings, which are good for transport, don't come up often because you can JSON encode an HTTP body. But one potential use-case for JSON stringify is Multipart Post, which AlamoFire nows supports.
How to convert array to json String in swift 2.3
var yourString : String = ""
do
{
if let postData : NSData = try NSJSONSerialization.dataWithJSONObject(yourArray, options: NSJSONWritingOptions.PrettyPrinted)
{
yourString = NSString(data: postData, encoding: NSUTF8StringEncoding)! as String
}
}
catch
{
print(error)
}
And now you can use yourSting as JSON string..
Swift 5
This generic extension will convert an array of objects to a JSON string from which it can either be:
saved to the App's Documents Directory (iOS/MacOS)
output directly to a file on the Desktop (MacOS)
.
extension JSONEncoder {
static func encode<T: Encodable>(from data: T) {
do {
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let json = try jsonEncoder.encode(data)
let jsonString = String(data: json, encoding: .utf8)
// iOS/Mac: Save to the App's documents directory
saveToDocumentDirectory(jsonString)
// Mac: Output to file on the user's Desktop
saveToDesktop(jsonString)
} catch {
print(error.localizedDescription)
}
}
static private func saveToDocumentDirectory(_ jsonString: String?) {
guard let path = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { return }
let fileURL = path.appendingPathComponent("Output.json")
do {
try jsonString?.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
}
static private func saveToDesktop(_ jsonString: String?) {
let homeURL = FileManager.default.homeDirectoryForCurrentUser
let desktopURL = homeURL.appendingPathComponent("Desktop")
let fileURL = desktopURL.appendingPathComponent("Output.json")
do {
try jsonString?.write(to: fileURL, atomically: true, encoding: .utf8)
} catch {
print(error.localizedDescription)
}
}
}
Example:
struct Person: Codable {
var name: String
var pets: [Pet]
}
struct Pet: Codable {
var type: String
}
extension Person {
static func sampleData() -> [Person] {
[
Person(name: "Adam", pets: []),
Person(name: "Jane", pets: [
Pet(type: "Cat")
]),
Person(name: "Robert", pets: [
Pet(type: "Cat"),
Pet(type: "Rabbit")
])
]
}
}
Usage:
JSONEncoder.encode(from: Person.sampleData())
Output:
This will create the following correctly formatted Output.json file:
[
{
"name" : "Adam",
"pets" : [
]
},
{
"name" : "Jane",
"pets" : [
{
"type" : "Cat"
}
]
},
{
"name" : "Robert",
"pets" : [
{
"type" : "Cat"
},
{
"type" : "Rabbit"
}
]
}
]
SWIFT 2.0
var tempJson : NSString = ""
do {
let arrJson = try NSJSONSerialization.dataWithJSONObject(arrInvitationList, options: NSJSONWritingOptions.PrettyPrinted)
let string = NSString(data: arrJson, encoding: NSUTF8StringEncoding)
tempJson = string! as NSString
}catch let error as NSError{
print(error.description)
}
NOTE:- use tempJson variable when you want to use.
extension Array where Element: Encodable {
func asArrayDictionary() throws -> [[String: Any]] {
var data: [[String: Any]] = []
for element in self {
data.append(try element.asDictionary())
}
return data
}
}
extension Encodable {
func asDictionary() throws -> [String: Any] {
let data = try JSONEncoder().encode(self)
guard let dictionary = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any] else {
throw NSError()
}
return dictionary
}
}
If you're using Codable protocols in your models these extensions might be helpful for getting dictionary representation (Swift 4)
Hint: To convert an NSArray containing JSON compatible objects to an NSData object containing a JSON document, use the appropriate method of NSJSONSerialization. JSONObjectWithData is not it.
Hint 2: You rarely want that data as a string; only for debugging purposes.
For Swift 4.2, that code still works fine
var mnemonic: [String] = ["abandon", "amount", "liar", "buyer"]
var myJsonString = ""
do {
let data = try JSONSerialization.data(withJSONObject:mnemonic, options: .prettyPrinted)
myJsonString = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
} catch {
print(error.localizedDescription)
}
return myJsonString
Swift 5
Make sure your object confirm Codable.
Swift's default variable types like Int, String, Double and ..., all are Codable that means we can convert theme to Data and vice versa.
For example, let's convert array of Int to String Base64
let array = [1, 2, 3]
let data = try? JSONEncoder().encode(array)
nsManagedObject.array = data?.base64EncodedString()
Make sure your NSManaged variable type is String in core data schema editor and custom class if your using custom class for core data objects.
let's convert back base64 string to array:
var getArray: [Int] {
guard let array = array else { return [] }
guard let data = Data(base64Encoded: array) else { return [] }
guard let val = try? JSONDecoder().decode([Int].self, from: data) else { return [] }
return val
}
Do not convert your own object to Base64 and store as String in CoreData and vice versa because we have something that named Relation in CoreData (databases).
For Swift 3.0 you have to use this:
var postString = ""
do {
let data = try JSONSerialization.data(withJSONObject: self.arrayNParcel, options: .prettyPrinted)
let string1:String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as! String
postString = "arrayData=\(string1)&user_id=\(userId)&markupSrcReport=\(markup)"
} catch {
print(error.localizedDescription)
}
request.httpBody = postString.data(using: .utf8)
100% working TESTED
You can try this.
func convertToJSONString(value: AnyObject) -> String? {
if JSONSerialization.isValidJSONObject(value) {
do{
let data = try JSONSerialization.data(withJSONObject: value, options: [])
if let string = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
return string as String
}
}catch{
}
}
return nil
}
I am working on an iOS weather app and need some help getting some values with JSON. I am trying to pull the value of id in the weather object. I am getting a value of nil when I debug. Could someone please help me with the logic? Here is the JSON request and Swift code.
{
"coord":{
"lon":138.93,
"lat":34.97
},
"weather":[
{
"id":800,
"main":"Clear",
"description":"clear sky",
"icon":"01n"
}
],
"base":"cmc stations",
"main":{
"temp":292.181,
"pressure":1005.21,
"humidity":100,
"temp_min":292.181,
"temp_max":292.181,
"sea_level":1014.59,
"grnd_level":1005.21
},
"wind":{
"speed":3.41,
"deg":78.0005
},
"clouds":{
"all":0
},
"dt":1464801034,
"sys":{
"message":0.003,
"country":"JP",
"sunrise":1464723086,
"sunset":1464774799
},
"id":1851632,
"name":"Shuzenji",
"cod":200
}
Here is my Swift snippet:
let requestURL: NSURL = NSURL(string: "http://api.openweathermap.org/data/2.5/weather?lat=35&lon=139&appid=6361e893fa064b1bfeaca686cd0929cc")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
print("JSON Downloaded Sucessfully.")
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let today = json["weather"] as? [[String: AnyObject]] {
//this is pulling 4 key value pairs
for weather in today {
let id = weather["id"] as? String
self.trumpDescription.text=id;
print(id)
}
}
}
catch {
print("Error with Json: \(error)")
}
}
}
task.resume()
}
The problem lies in your cast to a string. If you do not cast the id as a String, it will print "800" as an Int.
When you are grabbing the id from the json and converting it to a string, it reads the string and includes the new line character.
I played around in the playground
So you are correctly getting to the spot in the json, but you need to unwrap your optional.
You can also use the nil coalescing operator to unwrap optionals so you don't have to have a bunch of if lets:
let id = weather["id"] as? String ?? ""
Which will either set id to the value or to "" if it doesn't exist.
try this in your code:
let id = weather["id"]?.stringValue
instead of this:
let id = weather["id"] as? String
And see the magic!
Edit for explanation:
As this answer worked for you, let me tell you why it did.
The id is being sent as integer from the server side. When you do weather["id"] it returns object of type AnyObject?. When you do weather["id"] as? String the casting fails thus you were getting nil.
I'm trying to get data drom the json array, this is the code that i'm trying, the thing is that i would like to get only the name that is inside this json
{
"tag": "getuser",
"success": 1,
"error": 0,
"uid": "56108b7e651ad2.95653404",
"user": {
"name": "2",
"phone": "2",
"email": "2"
}
}
I tryied this
let jsonData:NSDictionary = try NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers ) as! NSDictionary
let name = jsonData["user"]
print("Nombre del usuarioes: \(name)")
But this prints the whole user data, name, phone and email, how can i be able to print only the name or only the email?
You don't have to use a library and you don't have to use key-value coding.
The same way you're already using subscripting for your dictionary with this:
let name = jsonData["user"]
you just have to continue subscripting to find your value.
Example:
do {
let jsonData = try NSJSONSerialization.JSONObjectWithData(urlData!, options: []) as! NSDictionary
let user = jsonData["user"]!
let name = user["name"]
print(name)
} catch {
print(error)
}
Even better with safe unwrapping:
do {
if let data = urlData, let jsonData = try NSJSONSerialization.JSONObjectWithData(data, options: []) as? NSDictionary {
if let user = jsonData["user"] as? NSDictionary, let name = user["name"] as? String {
print(name)
}
}
} catch {
print(error)
}
Note: in JSON, a dictionary is defined by {} and an array is defined by []. What you have here is a dictionary containing a dictionary, not an array (cf your question title).
A great library to decode json is SwiftyJSON
you can get sub-scripted data from the json like so
import SwiftyJSON
if let dataFromString = jsonString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) {
let json = JSON(data: dataFromString)
let name = json["user"]["name"].string
print(name)
}
Use your code, then get the field from jsonData by this:
let name = jsonData.valueForKeyPath("user.name") as! String
let email = jsonData.valueForKeyPath("user.email") as! String