Unwrapping Json Swift (found nil) - json

i currently trying to decode Json in Xcode, but i not succed to get one of them.
This is what i get :
[
{
"id": "1",
"title": "bmw",
"price": "500.00",
"description": "330",
"addedDate": "2015-05-18 00:00:00",
"user_id": "1",
"user_name": "CANOVAS",
"user_zipCode": "32767",
"category_id": "1",
"category_label": "VEHICULES",
"subcategory_id": "2",
"subcategory_label": "Motos",
"bdd": {}
}
"pictures":
[
{ "name": "http://cars.axlegeeks.com/sites/default/files/4315/media/images/2014_BMW_Z4_sDrive28i_3790993.jpg"
}
]
}
]
And i want to get the value of "name" for the "Pictures" lines but i have the error "unexpectedly found nil while unwrapping value".
For the others values i proceed this way :
let jsonData:NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options:NSJSONReadingOptions.MutableContainers , error: &error) as! NSDictionary
//Browse into JSON to get datas
let resp = jsonData["0"] as! NSDictionary
let user_nameR = resp["user_name"] as! String
let user_zipCodeR = resp["user_zipCode"] as! String
let titleR = resp["title"] as! String
let priceR = resp["price"] as! String
let descriptionR = resp["description"] as! String
Thank's for your help !

Pictures is in not in the subdictionary your other values are. This should work, but you should check all values if they are nil before you force cast them.
if let pictureArray = jsonData["pictures"] as? NSArray
{
if let pictureDict = pictureArray.firstObject as? NSDictionary
{
if let pictureName = pictureDict.objectForKey("name") as? String
{
NSLog("Picture name: %#", pictureName)
}
}
}
jsonData contains two sub-dictionaries, one without a key and one with key 'pictures'. Pictures is an array containing one sub-dictionary.

Related

JSON Decoding Error - typeMissmatch Swift 4

I'm trying to parse some data from JSON, I already got that working with another API but now I have another struct and I'm getting typeMissmatch Erros...
The JSON looks like:
{
"status": 200,
"data": {
"date": "2018-04-07T00:00:00.508Z",
"featured": [
{
"id": "2345",
"name": "name",
"price": "1,000",
"priceIcon": "String",
"priceIconLink": "URLString",
"images": {
"icon": "URLString",
"png": "URLString",
"gallery": "URLString",
"featured": "URLString"
},
"rarity": "1String",
"type": "1String",
"readableType": "1String"
}
],
"daily": [
{
"id": "12324",
"name": "name",
"price": "1,500",
"priceIcon": "String",
"priceIconLink": "URLString",
"images": {
"icon": "URLString",
"png": "URLString",
"gallery": "URLString",
"featured": "URLString"
},
"rarity": "1String",
"type": "1String",
"readableType": "1String"
}
]
}}
And a Codable struct like that:
struct Base : Codable {
let status : Int
let data : DataItems
}
struct DataItems : Codable {
let date : String
let featured : [Featured]
let daily : [Daily]
}
struct Featured : Codable {
let id : String
let name : String
let price : String
let priceIcon : String
let priceIconLink : String
let images : Images
let rarity : String
let type : String
let readableType : String
}
struct Daily : Codable {
let id : String
let name : String
let price : String
let priceIcon : String
let priceIconLink : String
let images : Images
let rarity : String
let type : String
let readableType : String
}
struct Images : Codable {
let icon : String
let png : String
let gallery : String
let featured : String
}
But when I try to decode that Json I get a "Swift.DecodingError.typeMismatch" Error:
▿ Swift.DecodingError.typeMismatch
▿ typeMismatch: (2 elements)
- .0: Swift.String #0
▿ .1: Swift.DecodingError.Context
▿ codingPath: 5 elements
- CodingKeys(stringValue: "data", intValue: nil)
- CodingKeys(stringValue: "daily", intValue: nil)
▿ _JSONKey(stringValue: "Index 0", intValue: 0)
- stringValue: "Index 0"
▿ intValue: Optional(0)
- some: 0
- CodingKeys(stringValue: "images", intValue: nil)
- CodingKeys(stringValue: "featured", intValue: nil)
- debugDescription: "Expected to decode String but found a number instead."
- underlyingError: nil
My JSON Decoder:
enum Result<Value> {
case success(Value)
case failure(Error)
}
func getItems(for userId: Int, completion: ((Result<Base>) -> Void)?) {
var urlComponents = URLComponents()
urlComponents.scheme = "https"
urlComponents.host = "api.jsonbin.io"
urlComponents.path = "/myurl"
let userIdItem = URLQueryItem(name: "userId", value: "\(userId)")
urlComponents.queryItems = [userIdItem]
guard let url = urlComponents.url else { fatalError("Could not create URL from components") }
var request = URLRequest(url: url)
request.httpMethod = "GET"
let config = URLSessionConfiguration.default
config.httpAdditionalHeaders = [
"secret-key": "xyz"
]
let session = URLSession(configuration: config)
let task = session.dataTask(with: request) { (responseData, response, responseError) in
DispatchQueue.main.async {
if let error = responseError {
completion?(.failure(error))
} else if let jsonDataTest = responseData {
// Now we have jsonData, Data representation of the JSON returned to us
// from our URLRequest...
// Create an instance of JSONDecoder to decode the JSON data to our
// Codable struct
let decoder = JSONDecoder()
do {
// We would use Post.self for JSON representing a single Post
// object, and [Post].self for JSON representing an array of
// Post objects
let posts = try decoder.decode(Base.self, from: jsonDataTest)
completion?(.success(posts))
} catch {
completion?(.failure(error))
}
} else {
let error = NSError(domain: "", code: 0, userInfo: [NSLocalizedDescriptionKey : "Data was not retrieved from request"]) as Error
completion?(.failure(error))
}
}
}
task.resume()
}
var base:Base?
func loadJson() {
getItems(for: 1) { (result) in
switch result {
case .success(let base):
self.base = base
dump(base)
case .failure(let error):
fatalError("error: \(error.localizedDescription)")
}
}
}
I'm new to swift and not sure what this Error is telling me or where the problem "decode String but found a number" is. I think there is something wrong with me struct.. I hope someone can help me there.
Please show the code where you want to parse the data to json.
let urlString = "your_url.json"
guard let url = URL(string: urlString) else { return }
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error!.localizedDescription)
}
guard let data = data else { return }
do {
//Decode retrived data with JSONDecoder and assing type of Article object
let baseData = try JSONDecoder().decode(Base.self, from: data)
print(baseData) //whole project
print(baseData.status) //200.0
print(baseData.data.date)
for day in baseData.data.daily {
print(day.id)
print(day.images.icon)
print(day.images.featured)
print(day.images.gallery)
print(day.images.png)
print(day.name)
print(day.price)
print(day.priceIcon)
print(day.priceIconLink)
print(day.rarity)
print(day.readableType)
print(day.type)
}
for feature in baseData.data.featured {
print(feature.id)
print(feature.images.icon)
print(feature.images.featured)
print(feature.images.gallery)
print(feature.images.png)
print(feature.name)
print(feature.price)
print(feature.priceIcon)
print(feature.priceIconLink)
print(feature.rarity)
print(feature.readableType)
print(feature.type)
}
} catch let jsonError {
print(jsonError)
}
}.resume()
I tried this and it works for me.
By the way I was a little bit confused that Featured and Daily have all the same variables but are different models.
EDIT
Your posted data in the question are valid. The json from https://api.jsonbin.io/b/5acbd2dc214f9a2b84c6f167/1 is wrong or not consistent.
There is "featured": false in Daily and in Featured it is a string. In the struct is a string expected. So you will get a mismatch. Once you try to parse a string (works) and then you try to parse a boolean to a string (error).

Swift: NSDictionary as NSArray

let voicemailFiles = voicemail.value( forKey: "voicemail") as! [AnyObject]
// Could not cast value of type '__NSDictionaryI' (0x10ca8a228) to 'NSArray' (0x10ca89d78)
let voicemailFiles = voicemail.value( forKey: "voicemail") as! [String : String]
// Could not cast value of type '__NSArrayI' (0x104df9448) to 'NSDictionary' (0x104df7fa8).
When trying to put the JSON ( as seen below) into a variable, i am hitting the above errors for the 2 methods of casting for "voicemail".
let config = voicemail.value(forKey: "config") as AnyObject
This line for the key of config works perfectly.
The variable of voicemail is an [AnyObject] value of the key, voicemailboxes
{
"voicemailboxes": [
{
"config": {
"id": "5",
"description": "Test"
},
"voicemail": [
{
"id": "id001",
"caller": "...",
"caller_UK": "...",
"called": "+...",
"called_UK": "...",
"received": "...",
"duration_seconds": "..."
},
{
"id": "id002",
"caller": "...",
"caller_UK": "...",
"called": "..."
}
]
}
]
}
voicemailboxes is an array of Dictionary.
voicemail is also an array of Dictionary.
Need to parse them appropriately.
On playground:
let json = """
{
"voicemailboxes": [
{
"config": {
"id": "5",
"description": "Test"
},
"voicemail": [
{
"id": "id001",
"caller": "...",
"caller_UK": "...",
"called": "+...",
"called_UK": "...",
"received": "...",
"duration_seconds": "..."
},
{
"id": "id002",
"caller": "...",
"caller_UK": "...",
"called": "..."
}
]
}
]
}
"""
let data = json.data(using: .utf8)!
let jsonDict = try! JSONSerialization.jsonObject(with: data, options: JSONSerialization.ReadingOptions.allowFragments) as! [String:Any]
let voicemailboxes = jsonDict["voicemailboxes"] as! [Any]
let voicemailboxesfirst = voicemailboxes.first as! [String:Any]
let voicemail = voicemailboxesfirst["voicemail"] as! [Any]
let voicemailfirst = voicemail.first as! [String:Any]
print(voicemailfirst)
Output:
["received": ..., "called": +..., "id": id001, "caller_UK": ..., "duration_seconds": ..., "caller": ..., "called_UK": ...]
As per your JSON it is clear that
voicemailboxes is [[string:Any]] (Array of Dictionary) and
voicemail is [[String:String]] (Array of Dictionary)
NOTE: guard or if let required to check correct response below is just example
You can access it like
((dictMain["voicemailboxes"] as! [[String:Any]]).first!["voicemail"] as! [[String:Any]])
Hope it is helpful to you
use below code
if let any = voicemail.value( forKey: "voicemail") {
if let tmpArray = any as? Array {
let voicemailFiles = tmpArray
}
}

How to get values nested within dictionary in NSDictionary?

I apologise if the title is unclear. I am not quite sure how exactly NSDictionary and JSON works.
I am trying to make a simple app using Swift that takes values from a .JSON file, and prints them out to the console. Here is my JSON file:
{
"students": [
{
"name": "Stew Dent",
"age": "10",
"year": 6,
"grades": [
{
"english": "a-plus",
"math": "b-plus"
},
{
"english": "a",
"math": "a-minus"
}
]
},
{
"name": "Mary Brown",
"age": "14",
"year": 10,
"grades": [
{
"english": "a-plus",
"math": "a-plus"
},
{
"english": "a-plus",
"math": "a"
}
]
}
]
}
Currently, I am able to retrieve the values of everything except the values in "grades". Here is my Swift code:
if let path = Bundle.main.path(forResource: "school", ofType: "json")
{
do {
// Retrieve data from JSON file
let jsonData = try NSData(contentsOfFile: path, options: .mappedIfSafe)
// Convert data into NSDictionary
let jsonResult = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
if let students : [NSDictionary] = jsonResult?["students"] as? [NSDictionary]
{
if let grades : [NSDictionary] = students["grades"] as? [NSDictionary]
{
for grade: NSDictionary in grades
{
for (subject, gradevalue) in grade
{
print ("\(subject): \(gradevalue)")
}
}
}
}
} catch
{
}
}
If I am not wrong, the "grades" is a dictionary inside the "students" dictionary. However, it fails to run the above code. On the "if let grades..." line, it gives the error message: "Cannot subscript a value of type '[NSDictionary]' with an index type of 'String'.
So what I am I doing wrong? Is there even any way to retrieve those values? Am I missing something? Any help would be greatly appreciated. Thanks :)
You should use Swift native types Data instead of NSData and Dictionary [String:Any] instead of NSDictionary. You also forgot to iterate through each student. Try like this:
do {
if let dict = try JSONSerialization.jsonObject(with: jsonData) as? [String: Any] {
print(dict)
if let students = dict["students"] as? [[String: Any]] {
print(students)
for student in students {
print(student["name"] ?? "")
if let grades = student["grades"] as? [[String: Any]] {
for grade in grades {
for (subject, gradevalue) in grade {
print ("student:",student["name"] ?? "", "subject:", subject, "grade:", gradevalue)
}
}
}
}
}
}
} catch {
print(error)
}
Try this code, this should work looking at what you are trying to do
if let path = Bundle.main.path(forResource: "student", ofType: "json")
{
do {
// Retrieve data from JSON file
let jsonData = try NSData(contentsOfFile: path, options: .mappedIfSafe)
// Convert data into NSDictionary
let jsonResult = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions.mutableContainers) as? NSDictionary
if let students = jsonResult?["students"] as? [NSDictionary]
{
for student in students
{
for grades in student["grades"] as! [[String:String]]{
for eachGrade in grades{
print("\(eachGrade.key) : \(eachGrade.value)")
}
}
}
}
}
catch
{
}
}

json traverse for Google Books API

I am having issues traversing a JSON retrieved from the Google Books API.
I am able to traverse and print the "id" from "items" but how do I get further down the json to print the "title" from "volumeInfo"?
Any tips or pointers appreciated.
JSON from Google:
{
"kind": "books#volumes",
"totalItems": 555,
"items": [
{
"kind": "books#volume",
"id": "BZXn-3QtQ_UC",
"etag": "Phnt2wzOFMo",
"selfLink": "https://www.googleapis.com/books/v1/volumes/BZXn-3QtQ_UC",
"volumeInfo": {
"title": "Revisiting Stephen King",
"subtitle": "A Critical Companion",
"authors": [
"Sharon A. Russell"
],
Swift Code
let url = NSURL(string: "https://www.googleapis.com/books/v1/volumes?q=stephen+king")
NSURLSession.sharedSession().dataTaskWithURL(url!) { (data, response, error) in
if error != nil {
print(error)
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers)
if json is [String: AnyObject] {
let items = json["items"] as? [[String: AnyObject]]
for item in items! {
let kind = item["id"] as? String
print(kind)
}
}
} catch let jsonError {
print(jsonError)
}
}.resume()
}
volumeInfo is Dictionary so you need to cast it like [String: AnyObject], and then get the title from that volumInfo Dictionary.
for item in items! {
let kind = item["id"] as? String
print(kind)
if let volumeInfo = item["volumeInfo"] as? [String: AnyObject] {
print(volumeInfo["title"])
}
}

Can't create dictionary from json in swift [duplicate]

This question already has answers here:
How to convert a JSON string to a dictionary?
(10 answers)
Closed 6 years ago.
I Have this json object which is downloaded by dataTaskWithRequest, i download it and serialize it like this:
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [String:AnyObject]
completion(json)
then the completion looks like this:
(let json) in
if let dict = JSON{
completion(dict)
}
and last completion looks like this:
(let response) in
dispatch_async(dispatch_get_main_queue()){
if let resp = response{
if resp["status"] as? Int == 0{
let user = resp["user"]
if let dict = user{
print(dict)
}
}
}
}
problem is that, it returns object like this:
{"created": "2016-06-01T10:49:54.096000",
"data_source": "1",
"display_name": "My Name",
"email": "Some#string.com",
"fb_id": "",
"first_name": "My",
"gender": "0",
"google_id": "",
"id": "SomeId",
"last_name": "Name",
"phone": "Number",
"updated": "2016-06-01T10:49:54.096000"}
when i try to cast this object in [String:AnyObject] it returns nil, and i can't get the values from this last object, can anybody help me with this, i've been trying to do this for like 4 hours and couldn't get it done
try this :
if let dictString = user as? String{
if let data = dictString.dataUsingEncoding(NSUTF8StringEncoding){
let dic = try! NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
print(dic)
}
}