Variable was never mutated...or Constant being used before initialized - ios

So I'm wanting to get jsonMeals data back and use it outside of this function.
However it seems no matter where I place my json variable I get an error. Changing it to a let does as well although a different one. Any insight would be greatly appreciated!
Error:
Constant 'json' used before being initialized // Variable 'json' was never mutated; consider changing to 'let' constant
func getApiDetailData(completed: #escaping () -> ()) {
var json: Any?
let urlString = "https://www.themealdb.com/api/json/v1/1/lookup.php?i=\(id)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
let json = try JSONSerialization.jsonObject(with: data!)
print("\(json)Testing")
DispatchQueue.main.async {
completed()
}
}
catch {
print("Error getting detail JSON data:\(error)")
}
guard let json = json as? [String : Any],
let jsonMeals = json["meals"] as? [String: Any] else {
print("No meals in json \(error?.localizedDescription)")
return
}
print("testing jsonMeals\(jsonMeals)")
}.resume()
}

try something like this example code:
func getApiDetailData(completed: #escaping () -> ()) {
// var json: Any? // <-- remove, never used
let urlString = "https://www.themealdb.com/api/json/v1/1/lookup.php?i=\(id)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!)
print("\(jsonData) Testing")
guard let json = jsonData as? [String : Any],
let jsonMeals = json["meals"] as? [[String: Any]] else {
print("No meals in json \(error?.localizedDescription)")
completed() // <-- here
return
}
print("testing jsonMeals \(jsonMeals)")
completed() // <-- here
}
catch {
print("Error getting detail JSON data:\(error)")
completed() // <-- here
}
}.resume()
}
Or, if you want to return the jsonMeals results:
func getApiDetailData(completed: #escaping ([[String: Any]]?) -> ()) { // <-- here
// var json: Any? // <-- remove, never used
let urlString = "https://www.themealdb.com/api/json/v1/1/lookup.php?i=\(id)"
let url = URL(string: urlString)
URLSession.shared.dataTask(with: url!) { (data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!)
print("\(jsonData) Testing")
guard let json = jsonData as? [String : Any],
let jsonMeals = json["meals"] as? [[String: Any]] else {
print("No meals in json \(error?.localizedDescription)")
completed(nil) // <-- here
return
}
print("testing jsonMeals \(jsonMeals)")
completed(jsonMeals) // <-- here
}
catch {
print("Error getting detail JSON data:\(error)")
completed(nil) // <-- here
}
}.resume()
}

Related

getting JSON values with swift

I have a url that I want get some json data from, when I load the URL in a webpage this is what the json looks like, how can I get these values in swift?
{
"name" : "name value"
"serial_number" : "serial_numbe value"
"status" : "status value"
...
}
this is what i've so far but it isn't working. I am getting an invalid conversion from throwing function of type... error on my URLSession.shared call
let web = URL(string: "192.168.101.1:8080/api")
let webRequest = URLRequest(url: web!)
URLSession.shared.dataTask(with: webRequest, completionHandler: {(data, response, error) in
guard let data = data, error == nil else {return}
do{
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String:Any]
let main = json as? [String : Any] ?? []
print(["name"])
}
})
You have syntax errors in there.
guard let web = URL(string: "192.168.101.1:8080/api") else { return }
URLSession.shared.dataTask(with: web) { (data, response, error) in
guard error == nil, let data = data else { return }
do {
let serializedData = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
guard let json = serializedData as? [String : Any] else { return }
print(json["name"])
} catch {
debugPrint(error)
}
}.resume()
You can try
let web = URL(string: "192.168.101.1:8080/api")
let webRequest = URLRequest(url: web!)
URLSession.shared.dataTask(with: webRequest, completionHandler: {(data, response, error) in
guard let data = data, error == nil else {return}
do{
let main = try JSONSerialization.jsonObject(with: data) as! [String:Any]
print(main["name"])
// or
let dec = JSONDecoder()
dec.keyDecodingStrategy =.convertFromSnakeCase
let res = dec.decode(Root.self, from: data)
}
catch {
print(error)
}
}).resume()
struct Root: Codable {
let name, serialNumber, status: String
}

Reading countries names from JSON file problem

I am trying to load and parse countries names from json file using swift but I can't
This is file's format which I try to read: Countries JSON File
My code to do this task:
func getJsonFromUrl(){
let url = NSURL(string: COUNTRIES_URL)
URLSession.shared.dataTask(with: (url as URL?)!, completionHandler: {(data, response, error) -> Void in
if let jsonObj = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? NSDictionary {
if let countries_array = jsonObj!.value(forKey: "name") as? NSArray {
for country in countries_array {
if let countryDict = country as? NSDictionary {
if let name = countryDict.value(forKey: "name") {
self.countries_names.append((name as? String)!)
}
}
}
}
OperationQueue.main.addOperation ({
self.showNames()
})
}
}).resume()
}
But when I run it, it gives me an error in this line: if let countries_array = jsonObj!.value(forKey: "name") as? NSArray {
because of an unexpected nil.
The JSON starts with a bracket ([) therefore the root object is an array
Don't use NSURL, NSArray and NSDictionary and value(forKey in Swift.
And handle possible errors.
func getJsonFromUrl() {
let url = URL(string: COUNTRIES_URL)!
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
if let error = error { print(error); return }
do {
if let countriesArray = try JSONSerialization.jsonObject(with: data!) as? [[String:String]] {
for country in countriesArray {
self.countries_names.append(country["name"]!)
}
}
} catch { print(error) }
OperationQueue.main.addOperation ({
self.showNames()
})
}).resume()
}
Or much more convenient with Decodable
struct Country : Decodable {
let name : String
}
func getJsonFromUrl() {
let url = URL(string: COUNTRIES_URL)!
URLSession.shared.dataTask(with: url!, completionHandler: {(data, response, error) -> Void in
if let error = error { print(error); return }
do {
let countries = try JSONDecoder().decode([Country].self, from: data!)
self.countries_names = countries.map{$0.name}
} catch { print(error) }
OperationQueue.main.addOperation ({
self.showNames()
})
}).resume()
}
It's an array not dictionary you need
if let dat = data {
if let jsonObj = try? JSONSerialization.jsonObject(with: dat, options:[]) as? [[String:String]]{
jsonObj.forEach { print($0["name"]) }
}
or use Codable
let res = try? JSONDecoder().decode([[String:String]].self,from:data)
or with model
struct Root: Codable {
let name : String
}
let res = try? JSONDecoder().decode([Root].self,from:data)

Parse image from web json

I have a json file that looks something like this:
{
"adTitle": "My Title",
"adURL": "https://mylink.com/",
"adImageURL": "http://mywebsite/bannerx#3x.png"
}
I get the JSON value from website: http://mywebsite.com/file.json
The problem is that the ad somehow doesn't load the adImageURL, so when I press the UIImageView, but when I press the area that then UIImageView should be, it open my adURL. This is the code I use for JSON:
var imageURL:String = "http://mywebsite/bannerx#3x.png"
var adURL:String = "https://mylink.com/"
func loadAdvertisement() {
// Set up the URL request
let todoEndpoint: String = "http://mywebsite.com/file.json"
guard let url = URL(string: todoEndpoint) else {
print("Error: cannot create URL")
return
}
let urlRequest = URLRequest(url: url)
// set up the session
let config = URLSessionConfiguration.default
let session = URLSession(configuration: config)
// make the request
let task = session.dataTask(with: urlRequest) {
(data, response, error) in
// check for any errors
guard error == nil else {
// print("error calling GET on /todos/1")
// print(error!)
return
}
// make sure we got data
guard let responseData = data else {
print("Error: did not receive data")
return
}
// parse the result as JSON, since that's what the API provides
do {
guard (try JSONSerialization.jsonObject(with: responseData, options: []) as? [String: AnyObject]) != nil else {
print("error trying to convert data to JSON")
return
}
let json = try JSONSerialization.jsonObject(with: responseData, options:.allowFragments) as! [String:AnyObject]
if (json != nil) {
self.imageURL = (json["adImageURL"] as? String)!
self.adURL = (json["adURL"] as? String)!
print(self.imageURL)
print(self.adURL)
DispatchQueue.main.async { () -> Void in
self.loadAdImage(self.imageURL)
}
}
} catch {
print("error trying to convert data to JSON")
return
}
}
task.resume()
// let jsonURL = URL(string: "http://mywebsite.com/file.json")
// self.getDataFromUrl(jsonURL!, completion: (data:Data?, response:URLResponse?, error:Error?)) -> Void
}
func loadAdImage(_ url:String) {
getDataFromUrl(URL(string: url)!) { (data, response, error) in
DispatchQueue.main.async { () -> Void in
guard let data = data, error == nil else { return }
print(response?.suggestedFilename ?? "")
print("Download Finished")
self.advertImageView.image = UIImage(data: data)
}
}
}
func getDataFromUrl(_ url:URL, completion: #escaping ((_ data: Data?, _ response: URLResponse?, _ error: NSError? ) -> Void)) {
URLSession.shared.dataTask(with: url) { (data:Data?, response:URLResponse?, error:Error?) in
completion(data, response, error as NSError?)
}.resume()
}
In the event LOG, is prints out both of the print("error trying to convert data to JSON") commands. I have used this code before in my project, and it worked just fine, but I have no idea why it wont work anymore.
Add the message to catch and check what actually error you are getting like this way:
do {
let json = try JSONSerialization.jsonObject(with: responseData, options:.allowFragments) as! [String:AnyObject]
} catch let message {
print("error trying to convert data to JSON" + "\(message)")
return
}

How parse JSON from 2 URLs properly?

I need to parse JSON from 2 different URL's
let jsonUrlStr1 = "https://123"
let jsonUrlStr2 = "https://325"
guard let url1 = URL(string: jsonUrlStr1) else { return }
guard let url2 = URL(string: jsonUrlStr2) else { return }
Here I'm running session for 1st url:
URLSession.shared.dataTask(with: url1) { (data, response, err) in
if err != nil {
print("Error:\(String(describing: err))")
}
guard let data = data else { return }
do {
let myData1 = try JSONDecoder().decode(SomeJsonModel1.self, from: data)
//Some code
} catch let jsonErr {
print("Error:\(jsonErr)")
}
}.resume()//URLSession
And then again, I'm running another session for 2nd url, using the same way:
URLSession.shared.dataTask(with: url2) { (data, response, err) in
if err != nil {
print("Error:\(String(describing: err))")
}
guard let data = data else { return }
do {
let myData2 = try JSONDecoder().decode(SomeJsonModel2.self, from: data)
//Some code
} catch let jsonErr {
print("Error:\(jsonErr)")
}
}.resume()//URLSession
This code works and I get the result.
But I think there should be a more correct way to parse 2 URLs.
Please advise how to do it correctly. Thanks.
You can try using completion block like this :
func getDataFromJson(url: String, completion: #escaping (_ success: [String : Any]) -> Void) {
let request = URLRequest(url: URL(string: url)!)
let task = URLSession.shared.dataTask(with: request) { Data, response, error in
guard let data = Data, error == nil else { // check for fundamental networking error
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print(response!)
return
}
let responseJSON = try! JSONSerialization.jsonObject(with: data, options: .allowFragments) as! [String : Any]
completion(responseJSON)
}
task.resume()
}
and call method like this :
let jsonUrlStr1 = "https://123"
let jsonUrlStr2 = "https://325"
getDataFromJson(url: jsonUrlStr1, completion: { response in
print("JSON response for url1 :: ",response) // once jsonUrlStr1 get it's response call next API
getDataFromJson(url: jsonUrlStr2, completion: { response in
print("JSON response for url2 :: ",response)
})
})

Json and variable scope

My error should be quite obvious but I can't find it;
I've a global variable initialized a the beginning of my class:
class InscriptionStageViewController: UIViewController, UIPickerViewDelegate, UIPickerViewDataSource {
var lesSemaines = [String]()
I try to populate this array with a distant json file using that function
func getSemainesStages(){
let url = URL(string: "http://www.boisdelacambre.be/ios/json/semaines.json")
let task = URLSession.shared.dataTask(with: url!){ (data, response, error) in
if let content = data {
do {
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
let listeSemaines = myJson["semaine"] as! [[String:AnyObject]]
//print(listeSemaines)
for i in 0...listeSemaines.count-1 {
var tabSem = listeSemaines[i]
let intituleSemaine:String = tabSem["intitule"] as! String
//let dateSemaine:String = tabSem["date"] as! String
DispatchQueue.main.sync
{
self.lesSemaines.append(intituleSemaine)
}
}
} catch
{
print("erreur Json")
}
}
}
task.resume()
}
When I call my function in the viewDidLoad and then I print my global array, it's empty (the URL is correct, the json data is read correctly and when I read the data appended in the array in the loop, it print the (so) needed value...)
Thanks in advance
The download takes time. Introduce another methode:
func updateUi() {
print(lesSemaines)
//pickerView.reloadAllComponents()
}
And call it after the download finished:
func getSemainesStages(){
// ... your code
let task = URLSession.shared.dataTask(with: url!){ (data, response, error) in
// ... your code
for tabSem in listeSemaines{
guard let intituleSemaine = tabSem["intitule"] as? String else {
print("erreur Json")
continue
}
self.lesSemaines.append(intituleSemaine)
}
// update UI *after* for loop
DispatchQueue.main.async {
updateUi()
}
// ... your code
}
}
I have updated your code to Swift 3. Please replace it with below code.
func getSemainesStages(){
let url = URL(string: "http://www.boisdelacambre.be/ios/json/semaines.json")
let task = URLSession.shared.dataTask(with: url!){ (data, response, error) in
if let content = data {
do {
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: Any]
let listeSemaines = myJson["semaine"] as! [[String: Any]]
for i in 0...listeSemaines.count-1 {
var tabSem = listeSemaines[i]
let intituleSemaine:String = tabSem["intitule"] as! String
self.lesSemaines.append(intituleSemaine)
}
print(self.lesSemaines)
} catch {
print("erreur Json")
}
}
}
task.resume()
}

Resources