Reading in a JSON File Using Swift
Follow the below code :
if let path = NSBundle.mainBundle().pathForResource("test", ofType: "json")
{
if let jsonData = NSData(contentsOfFile: path, options: .DataReadingMappedIfSafe, error: nil)
{
if let jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(jsonData, options: NSJSONReadingOptions.MutableContainers, error: nil) as? NSDictionary
{
if let persons : NSArray = jsonResult["person"] as? NSArray
{
// Do stuff
}
}
}
}
The array "persons" will contain all data for key person. Iterate throughs to fetch it.
Swift 4.0:
if let path = Bundle.main.path(forResource: "test", ofType: "json") {
do {
let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
let jsonResult = try JSONSerialization.jsonObject(with: data, options: .mutableLeaves)
if let jsonResult = jsonResult as? Dictionary<String, AnyObject>, let person = jsonResult["person"] as? [Any] {
// do stuff
}
} catch {
// handle error
}
}
Parsing data from local JSON file (SWIFT)
First of all lets look into you decoding flow step by step.
Decoding
- If you are executing this code directly in your app target, and not in some separate library, for the sake of simplicity you can use
Bundle.main
to access the path of the json file
guard let path = Bundle.main.path(forResource: "questions", ofType: "json") else {
return
}
- To decode the json we want the data to pass it to the decoder, and we can do it without having it converted to string so lets initialise
Data
directly from url.
let data = try Data(contentsOf: path)
- Since we are decoding multiple
QnAns
objects, the type passed to the decoder needs to beArray
ofQnAns
so we write it like that:
let result = try JSONDecoder().decode([QsAns].self, from: data)
both
[QsAns]
andArray<QsAns>
mean the same
- There are many errors that can occur during this flow and
do-catch
statements make it easy to debug by passing us the exact error that was thrown at us, so lets take advantage of that and print it in thecatch
closure like so:
catch { print(error) }
Final Flow
With all that in mind we land with a pretty elegant code that is also not very long and reads nicely:
guard let path = Bundle.main.path(forResource: "questions", ofType: "json") else {
return
}
do {
let data = try Data(contentsOf: path)
let result = try JSONDecoder().decode([QsAns].self, from: data)
} catch {
print(error)
}
Cool! Is that all?
Unfortunately your json does not looks like its valid for decoder to read and be able to figure out its contents. To make it work we need to embed the objects into the array.
So instead of:
{ ... },
{ ... }
We need
[
{ ... },
{ ... }
]
Ooof!
That should be pretty much it. Let me know how it goes, I will be happy to update the answer if something is not clear of there are still some issues. Good luck!
Bonus Question!
We can easily convert these two arrays into the dictionary by using zip
function
// type of dict will be [String: [String]]
let dict = Dictionary(uniqueKeysWithValues: zip(questions, answers))
Parsing JSON file using Swift
Make sure to add What hasn't worked for you and what you have tried? As a New contributor you need to learn how to post questions. Give it a try with my below answer.
Use Codable
to parse the JSON
like below,
let welcome = try? newJSONDecoder().decode(Welcome.self, from: jsonData)
// Welcome
struct Welcome: Codable {
let team11: Team11
enum CodingKeys: String, CodingKey {
case team11 = "Team11"
}
}
// Team11
struct Team11: Codable {
let results: [String: [Result]]
let tn, division: String
}
// Result
struct Result: Codable {
let g, n: String
}
Note: Your JSON is missing open and ending curly brackets, and I've updated that in your question.
How to parse a JSON file in swift?
This answer was last revised for Swift 5.3 and iOS 14.4 SDK.
Given some already obtained JSON data, you can use JSONDecoder
to decode it into your Decodable
model (or a collection of models).
let data: Data = /* obtain your JSON data */
let model = try JSONDecoder().decode(Model.self, from: data)
Such model must conform to the Decodable
protocol and contain correct mapping between properties and JSON dictionary keys. As an example, consider the following JSON array containing search results of cities beginning with "Wa".
[
{
"id": 123,
"city": "Washington",
"region": "D.C.",
"country": "United States"
},
{
"id": 456,
"city": "Warsaw",
"region": "Mazowieckie",
"country": "Poland"
},
...
]
For that, you need to create a model that contains the correct properties of correct types. If you're using a web API, its documentation will be of great help here.
struct SearchResult: Decodable {
let id: Int
let city: String
let region: String
let country: String
}
Then decode the data with JSONDecoder
:
let results = try JSONDecoder().decode([SearchResult].self, from: data)
Given a new array of decoded search results, call one of UITableView
's functions to reload its data. Note that the decode
function can throw an error which you must somehow handle.
To learn more about decoding custom types in Swift and more advanced usage of the Codable
APIs, I recommend checking out this documentation article.
how to parse json data from local files?
Please note that variable JSON
in your code is an array of objects.
You have to cast it properly.
func jsonTwo(){
let url = Bundle.main.url(forResource: "car_list", withExtension: "json")!
let data = try! Data(contentsOf: url)
let JSON = try! JSONSerialization.jsonObject(with: data, options: [])
print(".........." , JSON , ".......")
if let jsonArray = JSON as? [[String: Any]] {
for item in jsonArray {
let brand = item["brand"] as? String ?? "No Brand" //A default value
print("=======",brand,"=======")
}
}
}
Parsing a JSON file in Swift
The real problem with your code is the non-existent error handling when decoding, you need to rewrite that part so that it catches and prints any errors
if let data = data {
do {
let Recipes = try Recipe_Decoder.decode(Hit.self, from: data)
completion(Recipes.hits)
}
else {
print(error)
completion(nil)
}
}
If you change to this type of error handling you will get a lot of information from the error which in this case was
keyNotFound(Recipe_Coding_Keys(stringValue: "label", intValue: nil), Swift.DecodingError.Context(codingPath: [CodingKeys(stringValue: "hits", intValue: nil), _JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key Recipe_Coding_Keys(stringValue: \"label\", intValue: nil) (\"label\").", underlyingError: nil))
Which tells us that the decoder can't find the key "label" inside "hits" and this is because you are missing one level in your data structure for the key "recipe"
How do I parse JSON file with an array of objects in Swift?
Two points worth mentioning here
- The response you are trying to parse should come from https://coronavirus-19-api.herokuapp.com/countries not from https://corona-virus-stats.herokuapp.com/api/v1/cases/general-stats. So use first link instead of second.
let url = "https://coronavirus-19-api.herokuapp.com/countries"
getData(from: url)
- Since there are two fields with
null
values, mark them optional in your model.
struct CoronaData: Codable {
let country: String
let cases: Int
let todayCases: Int
let deaths: Int
let todayDeaths: Int
let recovered: Int?
let active: Int?
let critical: Int
let casesPerOneMillion: Int
let deathsPerOneMillion: Int
let totalTests: Int
let testsPerOneMillion: Int
}
How to get data from local JSON file in swift?
You have to take care of the JSON
structure to get the correct values. See the below snippet to see how you can reach your questions in JSON
.
let url = Bundle.main.url(forResource: "File", withExtension: "txt")!
do {
let jsonData = try Data(contentsOf: url)
let json = try JSONSerialization.jsonObject(with: jsonData) as! [[[String: Any]]]
if let question1 = json.first?[0] {
print( question1["link"] as! String)
}
if let question2 = json.first?[1] {
print( question2["link"] as! String)
}
}
catch {
print(error)
}
So now, you know how to reach the actual data. You should create some Question
class. Then you should retain a list of questions parsed from the file and use that list for your TableView
.
How to read local json file based on ID in ios swift?
Your JSON format is correct, just the double quotes you used to wrap keys and values seems wrong. Here is your working JSON:
{
"Telugu_songs": [{
"Id": 1,
"Title": "song1 title",
"Text": "song1 sample text"
},
{
"Id": 2,
"Title": "song2 title",
"Text": "song2 sample text"
},
{
"Id": 3,
"Title": "song3 title",
"Text": "song3 sample text"
}
],
"English_songs": [{
"Id": 1,
"Title": "song1 title",
"Text": "song1 sample text"
},
{
"Id": 2,
"Title": "song2 title",
"Text": "song2 sample text"
},
{
"Id": 3,
"Title": "song3 title",
"Text": "song3 sample text"
}
],
"Hindi_songs": [{
"Id": 1,
"Title": "song1 title",
"Text": "song1 sample text"
},
{
"Id": 2,
"Title": "song2 title",
"Text": "song2 sample text"
},
{
"Id": 3,
"Title": "song3 title",
"Text": "song3 sample text"
}
]
}
UPDATE:
Create a Codable class/struct and then store the JSON data in an array. You can then use increase array index +1, -1 based on your next previous button.
Related Topics
Can You Attach a Uigesturerecognizer to Multiple Views
Programmatically Retrieve Memory Usage on Iphone
Nsfilemanager.Defaultmanager().Fileexistsatpath Returns False Instead of True
Starting Iphone App Development in Linux
How to Apply Gradient to Background View of iOS Swift App
How to Get Current Location from User in Ios
Uploading File With Parameters Using Alamofire
Cell Spacing in Uicollectionview
How to Navigate Through Textfields (Next/Done Buttons)
How to Set the Cookies to Be Used by a Wkwebview
Number of Days Between Two Nsdates
Libc++Abi.Dylib: Terminating With Uncaught Exception of Type Nsexception (Lldb)