Parsing Json Files in Swift 3 - json

I would like to parse a local JSON file but I am unaware of how to do so in Swift 3
My Current Code doesn't seem to work
I keep receiving this error:
'jsonObject' produces 'Any', not the expected contextual result type 'NSArray'
import UIKit
import Alamofire
import SwiftyJSON
class ViewController: UIViewController
{
var allEntries: String!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func LoadAllQuestionsAndAnswers
{
let path = Bundle.main.path(forResource: "content", ofType: "json")
let jsonData : NSData = NSData(contentsOfFile: path!)!
allEntries = JSONSerialization.jsonObject(with: jsonData, options: JSONSerialization.ReadingOptions.mutableContainers, error: nil) as String
NSLog(allEntries)
}
}
I am loading the data from this json file "content.json"
[
{
"id" : "1",
"question": "What is the fastest fish in the ocean?",
"answers": [
"Sailfish",
"Lion Fish",
"Flounder",
"Tiger Shark",
"Swordfish"
],
"difficulty": "1"
},
{
"id" : "2",
"question": "Which animal has the most legs?",
"answers": [
"Millipede",
"Shrimp",
"Octopus",
"Dog",
"Lion"
],
"difficulty": "1"
}
]

let path = Bundle.main.path(forResource: "sample", ofType: "son")
let jsonData = try? NSData(contentsOfFile: path!, options: NSData.ReadingOptions.mappedIfSafe)
print(jsonData!)
let jsonResult: NSDictionary = try! JSONSerialization.jsonObject(with: jsonData as! Data, options: JSONSerialization.ReadingOptions.mutableContainers) as! NSDictionary
// save below sample json in a file and name it as sample.json
{
"blogs": [
{
"id": 111,
"url": "http://roadfiresoftware.com/blog/",
"name": "Roadfire Software Blog"
},
{
"id": 345,
"url": "https://developer.apple.com/swift/blog/",
"name": "Swift Developer Blog"
}
]
}

The root object of the JSON is an array
var allEntries = [[String:Any]]()
...
allEntries = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [[String:Any]]
mutableContainers is not needed at all in Swift

Related

For Loop with json decode data error requires 'People' to conform to 'Sequence'

I am new to swift . I created simple playground and added the file with extension json into playground . I am trying to decode the result and print the ID by using for loop but , I am getting following error ..
For-in loop requires 'People.Type' to conform to 'Sequence'
Here is my json file ..
{
"id": "1",
"options": [{
"id": "11",
"options": [{
"id": "111",
"options": []
}]
},
{
"id": "2",
"options": [{
"id": "21",
"options": []
},
{
"id": "22",
"options": [{
"id": "221",
"options": []
}]
}
]
}
]
}
Here is the code .. I tried ..
struct People: Codable {
let id: String
let options: [People]
}
func loadJson(filename fileName: String) -> People? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(People.self, from: data)
print("// Printing the ID of the Decode Json")
for jsondata in jsonData {
print("ID: \(jsonData.id)")
}
return jsonData
} catch {
print("error:\(error)")
}
}
return nil
}
loadJson(filename: "people1")
Here is the screenshot of the error ..
Here I got to run exactly what you are asking for, however I think you should probably consider renaming your struct to something like Person as #Vadian suggested.
struct People: Codable {
let id: String
let options: [People]
}
func loadJson(filename fileName: String) -> People? {
if let url = Bundle.main.url(forResource: fileName, withExtension: "json") {
do {
let data = try Data(contentsOf: url)
let decoder = JSONDecoder()
let jsonData = try decoder.decode(People.self, from: data)
printPeople(people: [jsonData])
return jsonData
} catch {
print("error:\(error)")
}
}
return nil
}
func printPeople(people: [People]) {
for person in people {
print(person.id)
if (!person.options.isEmpty) {
printPeople(people: person.options)
}
}
}
loadJson(filename: "people")
This will print:
1
11
111
2
21
22
221

Swift: Accessing the 1220 face vertices and save the vertices from AR face

I am trying to get the 1220 vertices data and save them to the iPhone file. The problem I am having is I could not get the captured data and write them into the JSON structure correctly.
I have:
struct CaptureData {
var vertices: [SIMD3<Float>]
var verticesFormatted : String {
let v = "<" + vertices.map{ "\($0.x):\($0.y):\($0.z)" }.joined(separator: "~") + "~t:\(String(Double(Date().timeIntervalSince1970)))>"
return "\(v)"
}
var jsonDict:Dictionary<String, Any> = [
"facetracking_data" : "1",
"info" : [
"frame" : "0",
"timestamp" : 12345,
"vertices" : [
"x" : "0.1",
"y" : "0.2",
"z" : "0.3"
]
]
]
var jsonData : Data {
let data = try! JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
return data
}
}
I was able to print some data using print(data), like following:
SIMD3(0.018364782, -0.043627884, 0.0480636), SIMD3(-0.01794959, -0.04421088, 0.04891427), SIMD3(-0.019180747, -0.045720913, 0.049276996)], jsonDict: ["facetracking_data": "1", "info": ["frame": "0", "timestamp": 1590426140.3919969, "vertices": ["x": "0.1", "y": "0.2", "z": "0.3"]]])
I am trying to write the captured data and save them into the JSON format by clicking one button:
#IBAction func saveButtonTapped(_ sender: UIButton) {
guard let data = getFrameData() else {return}
let jsonDataString = String(decoding: data.jsonData, as: UTF8.self)
let file = "\(UUID().uuidString).txt"
let dir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let fileURL = dir.appendingPathComponent(file)
do {
try data.write(to: fileURL, atomically: false, encoding: .utf8)
print(data)
}
catch {
print("Error: \(error)")
}
}
I could not get try data.write(to: fileURL, atomically: false, encoding: .utf8) this to work as it return error ('data' have no member of 'write') and I am not too sure how to get the captured data and write them into my defined JSON structure...

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
{
}
}

Read GeoJSON data from MongDB in Xcode 8.1 Swift 3?

I have a NodeJS API that queries a MongoDB cluster and returns nearby data in the following format. The issue is I can't enumerate the locations with Swift 3 and XCode 8.1.
[
{
"_id": "57b03fa32c6835946afd358c",
"location": {
"coordinates": [
144.2,
-34
],
"elevation": "1",
"type": "Point"
},
"name": "Resource 01",
"url": "http://www.url.com/Resource01.html"
},
{
"_id": "34b03fa32c6835946afd358c",
"location": {
"coordinates": [
154.2,
-35.3
],
"elevation": "1",
"type": "Point"
},
"name": "Resource 02",
"url": "http://www.url.com/Resource02.html"
}
]
This is my Query code.
let json = try! JSONSerialization.jsonObject(with: data)
print(json)
if let statusesArray = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let jsonbranch = statusesArray?[0] as? [String: AnyObject],
let therecord = jsonbranch["_id"] as? String {
print ("_id: " + therecord)
}
I tried to use SwiftyJSON but it does not work either?
Solved:
if let jsonBranch = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let name = jsonBranch?[0]["name"] as? String {
print ("name: " + name)
}
if let jsonBranch = try? JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [[String: AnyObject]],
let name = jsonBranch?[1]["name"] as? String {
print ("name: " + name)
}

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"])
}
}