Swift JSON Data - json

I received the JSON data as shown below, I want to get the "player_name" & "player_country" from this data. How do I get this?**enter image description here
In case, the image does not load, please refer the below output:
["team_key": 2611, "team_name": Leicester, "team_badge": https://apiv2.apifootball.com/badges/2611_leicester.png, "players": <__NSArrayI 0x600003331e00>(
{
"player_age" = 33;
"player_country" = Denmark;
"player_goals" = 0;
"player_key" = 140150332;
"player_match_played" = 30;
"player_name" = "Schmeichel Kasper";
"player_number" = 1;
"player_red_cards" = 0;
"player_type" = Goalkeepers;
"player_yellow_cards" = 2;
},
{
"player_age" = 23;
"player_country" = England;
"player_goals" = 3;
"player_key" = 2242127097;
"player_match_played" = 24;
"player_name" = "Chilwell Benjamin";
"player_number" = 3;
"player_red_cards" = 0;
"player_type" = Defenders;
"player_yellow_cards" = 2;
},
{.....}
I tried the following to get required data from this:
var mainArray = [[String: Any]]()
var tryArray = [[String]]()
for i in jsonArray {
if i["team_key"] as! String == teamID {
self.mainArray.append(i)
}
}
for i in self.mainArray {
self.tryArray.append(i["player_name"] as! [String])
}
I got this error with the above code:
Fatal error: Unexpectedly found nil while unwrapping an Optional value

let playerArray:NSDictionary = json as! NSDictionary
for var player in playerArray {
self.tryArray.append(player.objectForKey("player_name") as! String)
self.tryArray.append(player.objectForKey("player_country") as! String)
}

Thank you all for your response. I have tried this and it works.
var mainArray = NSArray()
var tryArray = [[String: Any]]()
for i in jsonArray {
if i["team_key"] as! String == teamID {
self.mainArray = i["players"] as! NSArray
}
}
for i in self.mainArray {
tryArray.append(i as! [String : Any])
}
What I did was I made mainArray as NSArray instead of [[String: Any]] and then copy it to tryArray which is of actually [[String: Any]] type and used tryArray for my work.
Thanks.

Related

Swift reading a json file

I am having this error. Cannot invoke 'jsonObject' with an argument list of type '(with: String, options: [Any])'
I am thinking it has to be a different type for the file but not sure.
I don't think doing bundle.main.url would be the correct way to do this. I had seen that in another question that suggested using url, but also not sure how it'd work. Any help would be appreciated, thanks.
This is code for writing into file in InfoViewController
let fileName: String?
let file: FileHandle? = FileHandle(forWritingAtPath: "fileName.json")
if file != nil {
// Set the data we want to write
do{
if let jsonData = try JSONSerialization.data(withJSONObject: fileName!, options: .init(rawValue: 0))
{
// Check if everything went well
//print(NSString(data: jsonData, encoding: 1)!)
let bookCover = (jsonData as AnyObject).value(forKeyPath: "bookCoverImage.image") as? [UIImage]
let bookTitle = (jsonData as AnyObject).value(forKeyPath: "bookTitleLabel.text") as? [String]
let author = (jsonData as AnyObject).value(forKeyPath: "authorLabel.text") as? [String]
let year = (jsonData as AnyObject).value(forKeyPath: "bookYear.text") as? [String]
let pages = (jsonData as AnyObject).value(forKeyPath: "numberOfPages") as? [String]
let ratingStars = (jsonData as AnyObject).value(forKeyPath: "ratingStars.image") as? [UIImage]
let reviews = (jsonData as AnyObject).value(forKeyPath: "totalReviews.text") as? [String]
let description = (jsonData as AnyObject).value(forKeyPath: "descriptionLabel.text") as? [String]
file?.write(jsonData)
// Do something cool with the new JSON data
}
}
catch {
}
// Write it to the file
// Close the file
file?.closeFile()
}
This is the code where the error is occurring. In favoritesListController.
var path: String?
var favoritesList: String?
var bookCoversDisplay = [UIImage]()
var titlesDisplay = [String]()
var authorsDisplay = [String]()
var yearDisplay = [String]()
var pagesDisplay = [String]()
var starRatingDisplay = [UIImage]()
var reviewsDisplay = [String]()
var descriptionsDisplay = [String]()
var bookCovers: UIImage!
var titles: String = ""
var authors: String = ""
var year: String = ""
var pages: String = ""
var starRating: UIImage!
var reviews: String = ""
var descriptions: String = ""
override func viewDidLoad() {
super.viewDidLoad()
path = Bundle.main.path(forResource: "favoritesList", ofType: "json")
do {
favoritesList = try String(contentsOfFile: path!)
let jsonResult = try? JSONSerialization.jsonObject(with: favoritesList, options: [])
if let array = jsonResult as? [Any] {
if let bookCover = array.first {
bookCoversDisplay = bookCover
} else if let title = array.second {
titlesDisplay = title
} else if let author = array.third {
authorsDisplay = author
} else if let year = array.fourth {
yearDisplay = year
} else if let pages = array.fifth {
pagesDisplay = pages
} else if let starRating = array.sixth {
starRatingDisplay = starRating
} else if let reviews = array.seventh {
reviewsDisplay = reviews
} else if let description = array.eighth {
descriptionsDisplay = description
}
}
maybe can help you:
do{
let data = try Data.init(contentsOf: URL.init(fileURLWithPath: Bundle.main.path(forResource: "Info", ofType: "json")!))
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
print(json)
}catch{
print(error)
}

Parsing JSON in Swift and accessing values?

I have successfully parsed JSON for:
birthday = "04/10/1986";
id = 202038339983;
location = {
city = Jupiter;
country = "United States";
state = FL;
};
My question is when part of the JSON is:
submissions = {
data = (
{
"created_time" = "2018-02-16T05:11:56+0000";
id = "131448394823824_167398094382256";
viewer = "Any random string and/or emojis";
},
{
"created_time" = "2018-02-14T23:36:41+0000";
id = "809809871824_8908987486899";
message = "vday \Ud83d\Udda4\U2665\Ufe0f";
});}
How am I supposed to access created_time, id, viewer, and message?
I have been able to print the whole submissions JSON response to the console with this code :
guard let jsonD = responseFromServer as? [String : Any] else {return}
let subs1 = (jsonD["submissions"] as? [String : Any])
let accessSubs1 = theSubs1
guard let parsedPost = theSubs1 else {
return
}
My console will display:
["data": <__NSArrayI 0x6040001a86c0>(
{
"created_time" = "2018-02-16T05:11:56+0000";
id = "131448394823824_167398094382256";
viewer = "Any random string and/or emojis";
},
{
"created_time" = "2018-02-14T23:36:41+0000";
id = "809809871824_8908987486899";
message = "vday \Ud83d\Udda4\U2665\Ufe0f";
})]
My question is how should I parse the JSON so I can access the created_time inside submissions?
Here is the HTTP Request:
struct XClass: RequestProtocol {
var Path = "/User"
var parameters: [String : Any]? = ["stuff": "id, birthday, location, submissions"]
var aToken = aToken.current
var httpMethod: RequestHTTPMethod = .GET
var apiVersion: APIVersion = .defaultVersion
struct Response: ResponseProtocol {
var id = String()
var birthday = String()
var city = String()
var state = String()
var country = String()
var viewSubs = [String : Any]()
init(XResponse: Any?) {
guard let jsonD = XResponse as? [String : Any] else {return}
id = (jsonD["id"] as? String)!
birthday = (jsonD["birthday"] as? String)!
let XArr = (jsonD["location"] as? [String : String])
city = XArr!["city"]!
country = XArr!["country"]!
state = XArr!["state"]!
let subs1 = (jsonD["submissions"] as? [String : Any])
let accessSubs1 = theSubs1
guard let parsedPost = theSubs1 else {
return
}
viewSubs = theSubs1
}}}
func getXData(){
let connection = RequestConnection()
connection.add(XClass()) { response, result in
switch result {
case .success(let response):
print("Request Succeeded: \(response)\n\n\n")
case .failed(let error):
print("Request Failed: \(error)")
}}
connection.start()
}
Create a struct
struct Data: Decodable {
var created_time : String
var id : String
var viewer : String
}
call to the api url from URLSession
guard let url = URL(string: "your api url")
URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil {
print(error.localizedDescription)
} else {
guard let data = data else {return}
var data: [Data]() = JSONDecoder().decode(Data.self, data)
for dat in data{
print(dat.created_time)
print(dat.id)
print(dat.viewer)
}
}
If you are not using Decodable from Swift 4, or still in Swift 3,
then you can specify that the data in "submissions" is an array of dictionaries (double brackets) then you can iterate that.
Change
let subs1 = (jsonD["submissions"] as? [String : Any])
To
let subs1 = (jsonD["submissions"] as? [[String : Any]])
for sub in subs1 {
let time = sub["created_time "] as? [String : Any]
...
}

Reading from JSON file in Swift

I'm trying to read a JSON file but I keep getting an error when I try to read the "ParsedText". First I convert the serialized JSON data to a dictionary of type [String: Any] and then I try to read the dictionary["ParsedResults"] value and convert that to a dictionary of type [String: Any] but it always fails.
Here is the JSON file:
{
ErrorDetails = "<null>";
ErrorMessage = "<null>";
IsErroredOnProcessing = 0;
OCRExitCode = 1;
ParsedResults = ( {
ErrorDetails = "";
ErrorMessage = "";
FileParseExitCode = 1;
ParsedText = "Sample text";
TextOverlay = {
HasOverlay = 0;
Lines = ( );
Message = "Text overlay is not provided as it is not requested";
};
} );
ProcessingTimeInMilliseconds = 869;
SearchablePDFURL = "Searchable PDF not generated as it was not requested.";
}
Here is part of the swift function:
do {
//create json object from data
let dictionary = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.allowFragments) as! [String: Any]
for (key, value) in dictionary {
print("KEY: \(key)")
print("VALUE: \(value)")
}
let parsedResults = dictionary["ParsedResults"] as! [String: Any]
print("parsedResults: \(parsedResults)")
} catch let error {
print("ERROR: Could not serialize jSON Data: \(error.localizedDescription)")
}
}
As already commented, your said-to-be JSON file is not in JSON format.
It seems to be in a classic text-based plist format. If you do want to read the file as is, you can use PropertyListSerialization:
import Foundation
let data = """
{
ErrorDetails = "<null>";
ErrorMessage = "<null>";
IsErroredOnProcessing = 0;
OCRExitCode = 1;
ParsedResults = ( {
ErrorDetails = "";
ErrorMessage = "";
FileParseExitCode = 1;
ParsedText = "Sample text";
TextOverlay = {
HasOverlay = 0;
Lines = ( );
Message = "Text overlay is not provided as it is not requested";
};
} );
ProcessingTimeInMilliseconds = 869;
SearchablePDFURL = "Searchable PDF not generated as it was not requested.";
}
""".data(using: .utf8)
do {
//create property list object from data
let dictionary = try PropertyListSerialization.propertyList(from: data!, options: [], format: nil) as! [String: Any]
for (key, value) in dictionary {
print("KEY: \(key)")
print("VALUE: \(value)")
}
let parsedResults = dictionary["ParsedResults"] as! [[String: Any]] //<- See Larme's comment.
print("parsedResults: \(parsedResults)")
} catch let error {
print("ERROR: Could not deserialize plist Data: \(error.localizedDescription)")
}
But I recommend you to check the part generating such files, and fix it to generate a valid JSON file.

Parsing JSON response in Swift/iOS

I have the following JSON.
[{"chatId":"1","user1_id":"1212","user2_id":"8543211123","user1_name":"dave","user2_name":"daveee","user1_profile_pic":"http:\/\/graph.facebook.com\/1212\/picture?type=large","user2_profile_pic":"https:\/\/scontent-waw1-1.xx.fbcdn.net\/v\/t1.0-9\/1212.jpg?oh=c288ac7b31a61aee751e8ddafb05e78a&oe=57DC702E","message":{"1":{"message_id":"24242241","sender":"1212","chatId":"1","text":"hello i am","timestamp":"2016-05-24 17:13:08"},"2":{"message_id":"421421","sender":"1212","chatId":"1","text":"great","timestamp":"2016-05-24 17:15:08"}}},{"chatId":"2","user1_id":"23413524635","user2_id":"1212","user1_name":"Leo","user2_name":"dave","user1_profile_pic":"https:\/\/scontent-fra3-1.xx.fbcdn.net\/v\/l\/t1.0-1\/1212.jpg?oh=1212&oe=579AE3AE","user2_profile_pic":"http:\/\/graph.facebook.com\/1212\/picture?type=large","message":{"1":{"message_id":"21321213","sender":"1212","chatId":"2","text":"yes, hi","timestamp":"2016-05-25 15:46:57"}}}]
I want to loop through the message and for each counter, extract the values. This is my code:
for anItem in jsonArray as! [Dictionary<String, AnyObject>]
var chat_messages : [Message]? = nil
var count_messages = 0;
if let dataArray = anItem["message"] as? [Int : Dictionary<String, AnyObject> ] {
for onemessage in dataArray as! [Dictionary<String, AnyObject>] {
let curr_message = Message()
if let messageid = onemessage["message_id"] as? String {
curr_message.id = messageid
}
if let messagedate = onemessage["timestamp"] as? NSDate {
curr_message.date = messagedate
}
if let messagesender = onemessage["sender"] as? String {
curr_message.sender = messagesender
}
if let messagetext = onemessage["text"] as? String {
curr_message.text = messagetext
}
chat_messages![count_messages] = curr_message
count_messages = count_messages + 1
}
}
The problem is that the line if let dataArray = anItem["message"] as? [Int : Dictionary<String, AnyObject> ] { always fails and the if condition is never entered.
If you are using NSJSONSerialization, then every dictionary is of the type: [String : AnyObject]. So this line:
if let dataArray = anItem["message"] as? [Int : Dictionary<String, AnyObject> ] {
should be:
if let dataArray = anItem["message"] as? [String : AnyObject] {
And to loop through the message dictionaries inside dataArray you could replace:
for onemessage in dataArray as! [Dictionary<String, AnyObject>] {
with:
for (_, messageDictionary) in dataArray {
if let onemessage = messageDictionary as? [String : AnyObject] {
and the rest of your code to get the various values out of the onemessage dictionary should work as you have it written now, except that this line will crash:
chat_messages![count_messages] = curr_message
Because you are forced unwrapping chat_messages, which you initialized as nil:
var chat_messages : [Message]? = nil
instead of as an empty array:
var chat_messages = [Message]()

swift parsing JSON data

so am trying to learn about JSON parsing, i want to extract some information from these fields..
index = 90;
property1 = {
href = "http://www.bodybuilding.com/exercises/detail/view/name/supine-one-arm-overhead-throw";
text = "Supine One-Arm Overhead Throw";
};
property2 = {
href = "http://www.bodybuilding.com/exercises/finder/lookup/filter/muscle/id/13/muscle/abdominals";
text = Abdominals;
};
property3 = (
{
href = "http://www.bodybuilding.com/exercises/detail/view/name/supine-one-arm-overhead-throw";
src = "http://www.bodybuilding.com/exercises/exerciseImages/sequences/839/Male/m/839_1.jpg";
text = "";
},
i can get a chunk of data, the problem is when i try to sort this information out... here is my code
func parseDictionary(dictionary: [String: AnyObject]) {
if let array: AnyObject = dictionary["results"] {
for resultDict in array as![AnyObject] {
if let resultDict = resultDict as? [String:AnyObject] {
if let wrapperType = resultDict["wrapperType"] as? String {
if let kind = resultDict["kind"] as? String {
print("wrapperType: \(wrapperType), kind: \(kind)")
}
}
} else {
print("expected a dictionary")
}
}
} else {
print("expected results array")
}
}
the error am getting is..
//Could not cast value of type '__NSCFDictionary' (0x1014c8a60) to //'NSArray' (0x1014c8470).
Your line:
for resultDict in array as![AnyObject] {
Needs to change to
for resultDict in array as![String: AnyObject] {
[AnyObject] is shorthand for Array<AnyObject>, whereas [String: AnyObject] is shorthand for Dictionary<String, AnyObject>, which explains your error.