Parse JSON from GoogleApiBooks - json

I'm trying to parse this JSON but it don't works.
This is the JSON:
{
"kind": "books#volumes",
"totalItems": 1,
"items": [
{
"kind": "books#volume",
"id": "uCHmPQAACAAJ",
"etag": "aBZ3KnoRsq4",
"selfLink": "https://www.googleapis.com/books/v1/volumes/uCHmPQAACAAJ",
"volumeInfo": {
"title": "Psicologia delle folle",
"authors": [
"Gustave Le Bon"
],
"publishedDate": "2004",
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "8850206240"
},
{
"type": "ISBN_13",
"identifier": "9788850206247"
}
],
"readingModes": {
"text": false,
"image": false
},
"pageCount": 251,
"printType": "BOOK",
"categories": [
"Psychology"
],
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "preview-1.0.0",
"language": "it",
},
"saleInfo": {
"country": "IT",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "IT",
"viewability": "NO_PAGES",
"embeddable": false,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": false
},
"pdf": {
"isAvailable": false
},
,
"accessViewStatus": "NONE",
"quoteSharingAllowed": false
}
}
]
}
And this is the code that i'm using:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var url = "https://www.googleapis.com/books/v1/volumes?q=isbn9788850206247&key=my-key"
Alamofire.request(url).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["items"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
print(self.arrRes)
}
if self.arrRes.count > 0 {
self.tableProva.reloadData()
}
}
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableProva.dequeueReusableCell(withIdentifier: "cellProva", for: indexPath) as! CellProvaClass
var dict = arrRes[indexPath.row]
cell.titleLabel?.text = dict["title"] as? String
cell.authorLabel?.text = dict["authors"] as? String
return cell
}
How can I solve this problem?

This is your JSON Reponse ( in short format) :
And this is the data structure (Array and dictionary format) :
Now you have to access : title and authors so here is your value in cellforRowAtIndexPath Method , a dictionary having name dict stores values of volumeInfo ( a Dictionary) :
so you have to use this way to access title :
cell.titleLabel?.text = dict["volumeInfo"]["title"] as? String
//To Fetch Author array
if let authorArray = dict["volumeInfo"]["authors"] as? NSArray{
print(authorArray)
}
and then to access author is an array so which index of value you want to show in cell.authorLabel .
In Second Screenshot those which are enclosed with {} is Dictionary and [] is Array
First try to show Title and then same way try to fetch value of author array and set according to your requirement.
Feel Free to comment if any further issue.

When you are parsing the JSON on line
if let resData = swiftyJsonVar["items"].arrayObject {
you will receive an object of NSDictionary which contains all other nested elements & arrays in keys. In your tableView delegate you are directly accessing the value from arrRes by unboxing it to NSDictionary object. All the entries are available in an array named items which further has a nested object volumeInfo which contains the info about title & another array of Authors.
You need to extract the further nested objects from arrRes object to use it in your tableView cellForRowAtIndex delegate function.
Let me know if you need any further help.

Related

How can I decode two different response JSON in one request?

I am trying to get response from Google's Book API. In there I can get response but for example, in some books have description or many other keys in response JSON. If I desing my structs according to with descriptions key, other books which not have description gave me dataCorrupted error and not decoding JSON. If I do otherwise, I get the same error on other books which have description. I hope I can explain myself. How can I solve it correctly?
Here my root class codable:
import Foundation
struct RootClass : Codable {
let items : [Item]?
let kind : String?
let totalItems : Int?
enum CodingKeys: String, CodingKey {
case items = "items"
case kind = "kind"
case totalItems = "totalItems"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
items = try values.decodeIfPresent([Item].self, forKey: .items)
kind = try values.decodeIfPresent(String.self, forKey: .kind)
totalItems = try values.decodeIfPresent(Int.self, forKey: .totalItems)
}
}
I need to reach root -> items -> volumeInfo.
And here Item codable struct:
import Foundation
struct Item : Codable {
let accessInfo : AccessInfo?
let etag : String?
let id : String?
let kind : String?
let saleInfo : SaleInfo?
let searchInfo : SearchInfo?
let selfLink : String?
let volumeInfo : VolumeInfo?
enum CodingKeys: String, CodingKey {
case accessInfo = "accessInfo"
case etag = "etag"
case id = "id"
case kind = "kind"
case saleInfo = "saleInfo"
case searchInfo = "searchInfo"
case selfLink = "selfLink"
case volumeInfo = "volumeInfo"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
accessInfo = try AccessInfo(from: decoder)
etag = try values.decodeIfPresent(String.self, forKey: .etag)
id = try values.decodeIfPresent(String.self, forKey: .id)
kind = try values.decodeIfPresent(String.self, forKey: .kind)
saleInfo = try SaleInfo(from: decoder)
searchInfo = try SearchInfo(from: decoder)
selfLink = try values.decodeIfPresent(String.self, forKey: .selfLink)
volumeInfo = try VolumeInfo(from: decoder)
}
}
And Here I parse json :
func parseJSON(searchData: Data) -> [SearchedModel]?{
let decode = JSONDecoder()
do{
let decodedData = try decode.decode(RootClass.self, from: searchData)
// IN HERE I CAN USE FOR LOOP TO ITEMS AND GET VOLUME INFO DATAS BUT ITS ALL NIL
return mainDataArr
}catch{
print(error)
return nil
}
}
When I try to loop over to items and get volume info datas its all nil. I can't understand why is this all nil? How can I solve it?
Here part of JSON 1 :
"kind": "books#volumes",
"totalItems": 1196,
"items": [
{
"kind": "books#volume",
"id": "4qnmsgEACAAJ",
"etag": "dYXW8bT6JB0",
"selfLink": "https://www.googleapis.com/books/v1/volumes/4qnmsgEACAAJ",
"volumeInfo": {
"title": "Sineklerin Tanrisi",
"authors": [
"William Golding"
],
"publishedDate": "2014-01-01",
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "9754582904"
},
{
"type": "ISBN_13",
"identifier": "9789754582901"
}
],
"readingModes": {
"text": false,
"image": false
},
"pageCount": 261,
"printType": "BOOK",
"categories": [
"Boys"
],
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "preview-1.0.0",
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api"
},
"language": "tr",
"previewLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&cd=1&source=gbs_api",
"infoLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&source=gbs_api",
"canonicalVolumeLink": "https://books.google.com/books/about/Sineklerin_Tanrisi.html?hl=&id=4qnmsgEACAAJ"
},
"saleInfo": {
"country": "TR",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "TR",
"viewability": "NO_PAGES",
"embeddable": false,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": false
},
"pdf": {
"isAvailable": false
},
"webReaderLink": "http://play.google.com/books/reader?id=4qnmsgEACAAJ&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "NONE",
"quoteSharingAllowed": false
}
}
And here JSON 2 (with same request's response):
"kind": "books#volumes",
"totalItems": 432,
"items": [
{
"kind": "books#volume",
"id": "yodWha1LmPsC",
"etag": "2bZz2CDqiq4",
"selfLink": "https://www.googleapis.com/books/v1/volumes/yodWha1LmPsC",
"volumeInfo": {
"title": "Momo the Monkey Arrives",
"authors": [
"Shariffa Keshavjee"
],
"publisher": "Master Publishing",
"publishedDate": "2012-09-21",
"description": "Momo the Monkey Arrives is the first in a series of illustrated children's books about the rescue of a monkey and how his presence livens up the household of two children: a boy and a girl. Along the way, as they take care of Momo, Geno and Alid learn how to give the best possible care to a monkey like him, and how to be more responsible children. The adventures of Momo are based on a true story.",
"industryIdentifiers": [
{
"type": "ISBN_13",
"identifier": "9789966158987"
},
{
"type": "ISBN_10",
"identifier": "9966158987"
}
],
"readingModes": {
"text": true,
"image": true
},
"pageCount": 28,
"printType": "BOOK",
"categories": [
"Juvenile Fiction"
],
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "1.4.4.0.preview.3",
"panelizationSummary": {
"containsEpubBubbles": false,
"containsImageBubbles": false
},
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.com.tr/books?id=yodWha1LmPsC&pg=PT25&dq=momo&hl=&cd=1&source=gbs_api",
"infoLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&source=gbs_api",
"canonicalVolumeLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC"
},
"saleInfo": {
"country": "TR",
"saleability": "FOR_SALE",
"isEbook": true,
"listPrice": {
"amount": 35.04,
"currencyCode": "TRY"
},
"retailPrice": {
"amount": 35.04,
"currencyCode": "TRY"
},
"buyLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&rdid=book-yodWha1LmPsC&rdot=1&source=gbs_api",
"offers": [
{
"finskyOfferType": 1,
"listPrice": {
"amountInMicros": 35040000,
"currencyCode": "TRY"
},
"retailPrice": {
"amountInMicros": 35040000,
"currencyCode": "TRY"
}
}
]
},
"accessInfo": {
"country": "TR",
"viewability": "PARTIAL",
"embeddable": true,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": true
},
"pdf": {
"isAvailable": true
},
"webReaderLink": "http://play.google.com/books/reader?id=yodWha1LmPsC&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "SAMPLE",
"quoteSharingAllowed": false
},
"searchInfo": {
"textSnippet": "<b>Momo</b> the Monkey Adventure Series <b>Momo</b> the Monkey Arrives <b>Momo</b> Makes a <br>\nMess <b>Momo</b> Comes to the Rescue <b>Momo</b> Moves to the Orphanage Look out for <br>\nthese stories about <b>Momo</b> and his friends. More coming soon! Master Publishing<br>\n ..."
}
}
The "data corrupted" error seems to be due to the presence of the \n in the textSnippet. If we take care of that manually, I can't reproduce any issue. Here is a complete (unlike your code) example that compiles and runs correctly in an iOS project, using the JSON you provided (patched up to be valid JSON):
let json1 = """
{
"kind": "books#volumes",
"totalItems": 1196,
"items": [
{
"kind": "books#volume",
"id": "4qnmsgEACAAJ",
"etag": "dYXW8bT6JB0",
"selfLink": "https://www.googleapis.com/books/v1/volumes/4qnmsgEACAAJ",
"volumeInfo": {
"title": "Sineklerin Tanrisi",
"authors": [
"William Golding"
],
"publishedDate": "2014-01-01",
"industryIdentifiers": [
{
"type": "ISBN_10",
"identifier": "9754582904"
},
{
"type": "ISBN_13",
"identifier": "9789754582901"
}
],
"readingModes": {
"text": false,
"image": false
},
"pageCount": 261,
"printType": "BOOK",
"categories": [
"Boys"
],
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "preview-1.0.0",
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=5&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=4qnmsgEACAAJ&printsec=frontcover&img=1&zoom=1&source=gbs_api"
},
"language": "tr",
"previewLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&cd=1&source=gbs_api",
"infoLink": "http://books.google.com.tr/books?id=4qnmsgEACAAJ&dq=sineklerin+tanrisi&hl=&source=gbs_api",
"canonicalVolumeLink": "https://books.google.com/books/about/Sineklerin_Tanrisi.html?hl=&id=4qnmsgEACAAJ"
},
"saleInfo": {
"country": "TR",
"saleability": "NOT_FOR_SALE",
"isEbook": false
},
"accessInfo": {
"country": "TR",
"viewability": "NO_PAGES",
"embeddable": false,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": false
},
"pdf": {
"isAvailable": false
},
"webReaderLink": "http://play.google.com/books/reader?id=4qnmsgEACAAJ&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "NONE",
"quoteSharingAllowed": false
}
}
]
}
"""
let json2 = """
{
"kind": "books#volumes",
"totalItems": 432,
"items": [
{
"kind": "books#volume",
"id": "yodWha1LmPsC",
"etag": "2bZz2CDqiq4",
"selfLink": "https://www.googleapis.com/books/v1/volumes/yodWha1LmPsC",
"volumeInfo": {
"title": "Momo the Monkey Arrives",
"authors": [
"Shariffa Keshavjee"
],
"publisher": "Master Publishing",
"publishedDate": "2012-09-21",
"description": "Momo the Monkey Arrives is the first in a series of illustrated children's books about the rescue of a monkey and how his presence livens up the household of two children: a boy and a girl. Along the way, as they take care of Momo, Geno and Alid learn how to give the best possible care to a monkey like him, and how to be more responsible children. The adventures of Momo are based on a true story.",
"industryIdentifiers": [
{
"type": "ISBN_13",
"identifier": "9789966158987"
},
{
"type": "ISBN_10",
"identifier": "9966158987"
}
],
"readingModes": {
"text": true,
"image": true
},
"pageCount": 28,
"printType": "BOOK",
"categories": [
"Juvenile Fiction"
],
"maturityRating": "NOT_MATURE",
"allowAnonLogging": false,
"contentVersion": "1.4.4.0.preview.3",
"panelizationSummary": {
"containsEpubBubbles": false,
"containsImageBubbles": false
},
"imageLinks": {
"smallThumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=5&edge=curl&source=gbs_api",
"thumbnail": "http://books.google.com/books/content?id=yodWha1LmPsC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api"
},
"language": "en",
"previewLink": "http://books.google.com.tr/books?id=yodWha1LmPsC&pg=PT25&dq=momo&hl=&cd=1&source=gbs_api",
"infoLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&source=gbs_api",
"canonicalVolumeLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC"
},
"saleInfo": {
"country": "TR",
"saleability": "FOR_SALE",
"isEbook": true,
"listPrice": {
"amount": 35.04,
"currencyCode": "TRY"
},
"retailPrice": {
"amount": 35.04,
"currencyCode": "TRY"
},
"buyLink": "https://play.google.com/store/books/details?id=yodWha1LmPsC&rdid=book-yodWha1LmPsC&rdot=1&source=gbs_api",
"offers": [
{
"finskyOfferType": 1,
"listPrice": {
"amountInMicros": 35040000,
"currencyCode": "TRY"
},
"retailPrice": {
"amountInMicros": 35040000,
"currencyCode": "TRY"
}
}
]
},
"accessInfo": {
"country": "TR",
"viewability": "PARTIAL",
"embeddable": true,
"publicDomain": false,
"textToSpeechPermission": "ALLOWED",
"epub": {
"isAvailable": true
},
"pdf": {
"isAvailable": true
},
"webReaderLink": "http://play.google.com/books/reader?id=yodWha1LmPsC&hl=&printsec=frontcover&source=gbs_api",
"accessViewStatus": "SAMPLE",
"quoteSharingAllowed": false
},
"searchInfo": {
"textSnippet": "<b>Momo</b> the Monkey Adventure Series <b>Momo</b> the Monkey Arrives <b>Momo</b> Makes a <br>\\nMess <b>Momo</b> Comes to the Rescue <b>Momo</b> Moves to the Orphanage Look out for <br>\\nthese stories about <b>Momo</b> and his friends. More coming soon! Master Publishing<br>\\n ..."
}
}
]
}
"""
struct Base : Codable {
let kind : String
let totalItems : Int
let items : [Items]
}
struct Items : Codable {
let kind : String
let id : String
let etag : String
let selfLink : String
let volumeInfo : VolumeInfo
let saleInfo : SaleInfo?
let accessInfo : AccessInfo
let searchInfo : SearchInfo?
}
struct SaleInfo : Codable {
let country : String
let saleability : String
let isEbook : Bool
let listPrice : ListPrice?
let retailPrice : RetailPrice?
let buyLink : String?
let offers : [Offers]?
}
struct Offers : Codable {
let finskyOfferType : Int
let listPrice : ListPrice
let retailPrice : RetailPrice
}
struct ListPrice : Codable {
let amountInMicros : Int?
let currencyCode : String
}
struct ReadingModes : Codable {
let text : Bool
let image : Bool
}
struct Epub : Codable {
let isAvailable : Bool
}
struct Pdf : Codable {
let isAvailable : Bool
}
struct RetailPrice : Codable {
let amountInMicros : Int?
let currencyCode : String
}
struct SearchInfo : Codable {
let textSnippet : String
}
struct ImageLinks : Codable {
let smallThumbnail : String
let thumbnail : String
}
struct IndustryIdentifiers : Codable {
let type : String
let identifier : String
}
struct PanelizationSummary : Codable {
let containsEpubBubbles : Bool
let containsImageBubbles : Bool
}
struct VolumeInfo : Codable {
let title : String
let authors : [String]
let publisher : String?
let publishedDate : String
let description : String?
let industryIdentifiers : [IndustryIdentifiers]
let readingModes : ReadingModes
let pageCount : Int
let printType : String
let categories : [String]
let maturityRating : String
let allowAnonLogging : Bool
let contentVersion : String
let panelizationSummary : PanelizationSummary?
let imageLinks : ImageLinks
let language : String
let previewLink : String
let infoLink : String
let canonicalVolumeLink : String
}
struct AccessInfo : Codable {
let country : String
let viewability : String
let embeddable : Bool
let publicDomain : Bool
let textToSpeechPermission : String
let epub : Epub
let pdf : Pdf
let webReaderLink : String
let accessViewStatus : String
let quoteSharingAllowed : Bool
}
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let data1 = json1.data(using: .utf8)!
do {
let result = try JSONDecoder().decode(Base.self, from: data1)
print("success1")
print(result)
} catch {
print(error)
}
let data2 = json2.data(using: .utf8)!
do {
let result = try JSONDecoder().decode(Base.self, from: data2)
print("success2")
print(result)
} catch {
print(error)
}
}
}

Accessing nested JSON [String: Any] object and appending to it

Using swift, I am attempting to access the "locations" object within the "locationConstraint" part of a JSON that looks like this:
let jsonObj : [String: Any] =
[
"attendees": [
[
"type": "required",
"emailAddress": [
"name": nameOfRoom,
"address": roomEmailAddress
]
]
],
"locationConstraint": [
"isRequired": "true",
"suggestLocation": "false",
"locations": [
[
"displayName": "First Floor Test Meeting Room 1",
"locationEmailAddress": "FirstFloorTestMeetingRoom1#onmicrosoft.com"
],
[
"displayName": "Ground Floor Test Meeting Room 1",
"locationEmailAddress": "GroundFloorTestMeetingRoom1#onmicrosoft.com"
]
//and the rest of the rooms below this..
]
],
"meetingDuration": durationOfMeeting,
]
I am attempting to add items to the locations from outside this method (to prevent repetitive code, as location list could be large) - but I am having problems replacing back into this part of the json..
My method to do this:
static func setupJsonObjectForFindMeetingTimeAllRoomsTest(nameOfRoom: String, roomEmailAddress: String, dateStartString: String, dateEndString: String, durationOfMeeting: String, locations: [String]) -> [String: Any] {
let jsonObj : [String: Any] =
[
"attendees": [
[
"type": "required",
"emailAddress": [
"name": nameOfRoom,
"address": roomEmailAddress
]
]
],
"meetingDuration": durationOfMeeting
]
let jsonObject = addLocationsToExistingJson(locations:locations, jsonObj: jsonObj)
return jsonObject
}
and my method to add locations to the existing json object:
static func addLocationsToExistingJson(locations: [String], jsonObj: [String: Any]) -> [String: Any] {
var data: [String: Any] = jsonObj
let locConstraintObj = [
"isRequired": "true",
"suggestLocation": "false",
"locations" : []
] as [String : Any]
//try access locationConstraint part of json
data["locationConstraint"] = locConstraintObj
for i in stride(from: 0, to: locations.count, by: 1) {
let item: [String: Any] = [
"displayName": locations[i],
"locationEmailAddress": locations[i]
]
// get existing items, or create new array if doesn't exist
//this line below wrong? I need to access data["locationConstraint]["locations"]
//but an error occurs when i change to the above.. .how do i access it?
var existingItems = data["locations"] as? [[String: Any]] ?? [[String: Any]]()
// append the item
existingItems.append(item)
// replace back into `data`
data["locations"] = existingItems
}
return data
}
So ultimately, my final json object that works should look like this:
["meetingDuration": "PT60M", "returnSuggestionReasons": "true",
"attendees": [["emailAddress": ["address":
"TestUser6#qubbook.onmicrosoft.com", "name": "N"], "type":
"required"]], "minimumAttendeePercentage": "100",
"locationConstraint": ["locations": [["displayName": "First Floor Test
Meeting Room 1", "locationEmailAddress":
"FirstFloorTestMeetingRoom1#qubbook.onmicrosoft.com"], ["displayName":
"Ground Floor Test Meeting Room 1", "locationEmailAddress":
"GroundFloorTestMeetingRoom1#qubbook.onmicrosoft.com"]],
"suggestLocation": "false", "isRequired": "true"], "timeConstraint":
["activityDomain": "unrestricted", "timeslots": [["start":
["dateTime": "2019-02-07 14:30:00", "timeZone": "UTC"], "end":
["dateTime": "2019-02-07 15:30:00", "timeZone": "UTC"]]]],
"isOrganizerOptional": "true"]
Where as it looks like this:
["timeConstraint": ["activityDomain": "unrestricted", "timeslots":
[["start": ["dateTime": "2019-02-08 08:30:00", "timeZone": "UTC"],
"end": ["dateTime": "2019-02-08 09:30:00", "timeZone": "UTC"]]]],
"locationConstraint": ["suggestLocation": "false", "locations": [],
"isRequired": "true"], "attendees": [["emailAddress": ["address":
"TestUser6#qubbook.onmicrosoft.com", "name": "N"], "type":
"required"]], "returnSuggestionReasons": "true",
"isOrganizerOptional": "true", "minimumAttendeePercentage": "100",
"locations": [["locationEmailAddress":
"FirstFloorTestMeetingRoom1#qubbook.onmicrosoft.com", "displayName":
"FirstFloorTestMeetingRoom1#qubbook.onmicrosoft.com"],
["locationEmailAddress":
"GroundFloorTestMeetingRoom1#qubbook.onmicrosoft.com", "displayName":
"GroundFloorTestMeetingRoom1#qubbook.onmicrosoft.com"]],
"meetingDuration": "PT60M"]
Where the locations object is being added outside the locationConstraint part of the JSON.. I know I need to be accessing the locationConstraint part of my json like this: var existingItems = data["locationConstraint"]!["locations"] as? [[String: Any]] ?? [[String: Any]]() but this returns an error:
Type 'Any' has no subscript members
This is my first time working with JSONs and trying to manipulate them in swift.. How would I go about fixing this?
Solution by using model objects and Codable
as trojanfoe proposed, you should use model objects and manipulate them directly.
import Foundation
struct Meeting: Codable {
var attendees: [Attendee]
var locationConstraint: LocationConstraint
var meetingDuration: Int
}
struct Attendee: Codable {
var type: Type
var emailAddress: EmailAdress
enum `Type`: String, Codable {
case required
}
}
struct LocationConstraint: Codable {
var isRequired: Bool
var suggestLocation: Bool
var locations: [Location]
}
struct EmailAdress: Codable {
var name: String
var address: String
}
struct Location: Codable {
var displayName: String
var locationEmailAddress: String
}
At first we take your dictionary...
let jsonDict: [String: Any] =
[
"attendees": [
[
"type": "required",
"emailAddress": [
"name": "specificName",
"address": "specificAdress"
]
]
],
"locationConstraint": [
"isRequired": true,
"suggestLocation": false,
"locations": [
[
"displayName": "First Floor Test Meeting Room 1",
"locationEmailAddress": "FirstFloorTestMeetingRoom1#onmicrosoft.com"
],
[
"displayName": "Ground Floor Test Meeting Room 1",
"locationEmailAddress": "GroundFloorTestMeetingRoom1#onmicrosoft.com"
]
]
],
"meetingDuration": 1800,
]
... and serialize it.
let jsonData = try JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
print(String(data: jsonData, encoding: String.Encoding.utf8))
We then decode it into our meeting model.
var meeting = try JSONDecoder().decode(Meeting.self, from: jsonData)
We initialize a new location and append it to our meeting.locationConstraints.locations array.
let newLocation = Location(displayName: "newDisplayName", locationEmailAddress: "newLocationEmailAdress")
meeting.locationConstraint.locations.append(newLocation)
And finally reencode our model object again.
let updatedJsonData = try JSONEncoder().encode(meeting)
print(String(data: updatedJsonData, encoding: String.Encoding.utf8))

Swift 3 parsing API response trouble

I'm trying to parse an API response in Swift an Im having trouble getting to nested objects and arrays in the response
here is my sample json
{
"Id": "10",
"Name": "PV Prediction By Site",
"Description": "",
"Permalink": "",
"Source_format": "JSON",
"Internal_function_name": "get-meteo-by-site",
"Additional_parameters": "Prediction",
"Sites": null,
"Data": [
{
"UTCDateString": "2017-05-01T20:10:33Z",
"Value": [
{
"metadata": {
"name": "Beck_Hill",
"latitude": 46.26,
"longitude": -112.44,
"height": 1926,
"timezone_abbrevation": "MDT",
"utc_timeoffset": -6,
"modelrun_utc": "2017-05-01 12:00",
"modelrun_updatetime_utc": "2017-05-01 16:41",
"kwp": 40.26,
"slope": 30,
"facing": 180,
"tracking": 0
},
"units": {
"time": "YYYY-MM-DD hh:mm",
"pvpower": "kW",
"snowcover": "mm",
"iam": "percent",
"temperature": "C"
},
"data_xmin": {
"time": [
"2017-05-01 07:00",
"2017-05-01 07:15",
"2017-05-01 07:30",
"2017-05-01 07:45",
"2017-05-01 08:00",
"2017-05-01 08:15",
"2017-05-01 08:30"
],
"pvpower_instant": [
40.26,
40.26,
40.26,
40.26,
40.26
]
}
}
]
}
]
}
And here is some of my parsing code, I can get to the first object in the "Data" array fine, but when i try to get the first object in the Value string it fails to convert the AnyObject to anything else
//get a Dictionary of sites
sitesDictionary = try JSONSerialization.jsonObject(with: decodedData, options: .allowFragments) as? [[String:AnyObject]]
CoreDataStack.sharedInstance.persistentContainer.performBackgroundTask({ (context) in
//loop thorugh all site and create SiteMO objects from them
for site in (sitesDictionary?.enumerated())! {
//SiteMO
let siteMO = SiteMO.siteInfo(siteInfo: site.element, inManagedObjectContext: context)!
let siteFeedsDictionary = site.element["Feeds"] as! [[String:AnyObject]]
//loop through every feed object and create FeedMO objects from them
for feed in siteFeedsDictionary.enumerated() {
//FeedMO
let feedMO = FeedMO.feedInfo(feedInfo: feed.element, site: siteMO, inManagedObjectContext: context)!
//what type of data is in the feed?
switch feedMO.additionalParameters! {
case "Weather":
//its a feed with a Weather object
print("There should be a WeatherMO created Here")
case "Prediction":
//its a feed with a Prediction object
let dataArray = feed.element["Data"] as? [[String:AnyObject]]
I need some data out of the "metadata" "units" and "data_xmin" objects
For metadata
result[“Data”][0][“Value”][0]

Repeated values in UITable cells from api json

After I do http call from api I get json file then I loop through it to get specific values:
if let value: AnyObject = response.result.value as AnyObject? {
let json = JSON(value)
for (key, subJson) in json {
let drivers = subJson["driver"]
for (key, subJson) in drivers {
let status = subJson["status"].stringValue
let date = subJson["created_at"].stringValue
let name = subJson["name"].stringValue
let pivot = subJson["pivot"]
for (key, subJson) in subJson["pivot"] {
let type = pivot["type"].stringValue
let data = Driverj(name: name, status: status, created_at: date)
self.data.append(data)
}
DispatchQueue.main.async {
self.tableview.reloadData()
}
}
}
}
in a separate file I connect the values with objects:
class DriverC: UITableViewCell {
#IBOutlet weak var status : UILabel!
#IBOutlet weak var date : UILabel!
#IBOutlet weak var job : UILabel!
#IBOutlet weak var update : UILabel!
}
And in another file I have the data saved :
import Foundation
import ObjectMapper
class Driverj : Mappable {
var status : String?
var name : String?
var created_at : String?
required init?(map: Map) {
}
required init(name: String , status : String , created_at : String ) {
self.status = status
self.name = name
self.created_at = created_at
}
func mapping(map: Map) {
status <- map["status"]
name <- map["name"]
created_at <- map["created_at"]
}
}
And finally here is how it's displayed
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "DriverCell", for: indexPath) as! DriverC
let entry = data[indexPath.row]
cell.date.text = entry.date
cell.job.text = entry.job
cell.status.text = entry.status
cell.update.text = entry.name
return cell
}
My question is when I run my project I get three cells with the same data repeated. Why ?
the json files :
[
{
"id": 4,
"name": null,
"email": "5#5.com",
"status": 0,
"confirmed": false,
"street": "street ",
"niehgborhood": "North",
"city": "Sf",
"national_id": "1009090",
"phone": "9000",
"size_of_house": null,
"created_at": "2016-12-04 13:55:52",
"updated_at": "2017-03-08 14:03:44",
"deleted_at": null,
"driver": [
{
"name": "unknown",
"age": "25",
"Smoker": "No",
"language": "English",
"religion": "Muslim",
"created_at": null,
"updated_at": "2017-03-08 13:48:55",
"status": "تم",
"pic": "http://localhost:8000/images/1488714520.jpg",
"id": 1,
"pivot": {
"user_id": 4,
"driver_id": 1,
"type": "driver"
}
},
{
"name": "Jae",
"age": "30",
"Smoker": "No",
"language": "English",
"religion": "Muslim ",
"created_at": "2017-02-28 09:36:15",
"updated_at": "2017-03-08 08:46:06",
"status": "ok",
"pic": "http://localhost:8000/images/1488714520.jpg",
"id": 2,
"pivot": {
"user_id": 4,
"driver_id": 2,
"type": "driver"

Alamofire json swift 2.2

I'm trying to take out some data of facebook place's names with Alamofire but i have no luck.
This is what i've tried and i cant figure out how to make it work.
xcode 7.3
swift2.2
So the result of the graph api is this
{
"data": [
{
"category": "Local business",
"category_list": [
{
"id": "272705352802676",
"name": "Outdoors"
},
{
"id": "115725465228008",
"name": "Region"
}
],
"location": {
"street": "Athens",
"city": "Palai\u00f3n F\u00e1liron",
"state": "",
"country": "Greece",
"zip": "17562",
"latitude": 37.9284637008,
"longitude": 23.6944070162
},
"name": "THE NAME OF THE PLACE",
"id": "THE ID"
}
and i want to go inside "data" and take only the name and the ID of the place which are the 2 last lines.
And this is my code!
override func viewDidLoad() {
super.viewDidLoad()
Alamofire.request(.GET, "https://graph.facebook.com/search", parameters: ["q": "", "type": "place", "center": "37.928319,23.7036673", "distance": "10000", "access_token": "ACCESS-TOKEN", "expires_in": "5184000"])
.responseJSON { response in
if let JSON = response.result.value {
print("JSON: \(JSON["data"]!["name"]!)")
}
}
}
and i get this error
fatal error: unexpectedly found nil while unwrapping an Optional value
Any idea why?
Ok this was easy i guess and it didn't worth the question but this is the solution
Alamofire.request(.GET, "https://graph.facebook.com/search", parameters: ["q": "", "type": "place", "center": "37.928319,23.7036673", "distance": "10000", "access_token": "475827182628380|6U-mk-1etGQHwrXRSMF4Ht2zOyc", "expires_in": "5184000"])
.responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) {
let swiftyJsonVar = JSON(responseData.result.value!)
if let resData = swiftyJsonVar["data"].arrayObject {
self.arrRes = resData as! [[String:AnyObject]]
}
if self.arrRes.count > 0 {
self.kati.reloadData()
}
}
}
And at the cell
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("checkInCell", forIndexPath: indexPath)
var dict = arrRes[indexPath.row]
cell.textLabel?.text = dict["name"] as? String
//cell.detailTextLabel?.text = dict["email"] as? String
return cell
}
Just dont forget to use SwiftyJSON too!