Reading countries names from JSON file problem - ios

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)

Related

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

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()
}

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
}

error at getting image from url?

let defaultConfiguration = URLSessionConfiguration.default
let operationQueue = OperationQueue.main
let defaultSession = URLSession(configuration: defaultConfiguration, delegate: self, delegateQueue: operationQueue)
if let url = URL(string: "https://newsapi.org/v1/articles?source=abc-news-au&sortBy=top&apiKey=47d2ce48babd47b1bc391b426b89ca23")
{
(defaultSession.dataTask(with: url) { (data, response, error) in
if error != nil{
return
}
do {
let resultJson = try JSONSerialization.jsonObject(with: data!, options: []) as? [String:AnyObject]
if var dataDictionary = resultJson {
// dataDictionary["access_token"] as AnyObject
self.dataArray = dataDictionary["articles"] as! [Any]
var dataDictionary22 = self.dataArray[0] as! [String: Any] as [String : AnyObject]
let url = URL(string:
"\(String(describing: dataDictionary22["urlToImage"]!))")
print("url -> \(String(describing: url!))")
let task = URLSession.shared.dataTask(with: url!) { data, response, error in
guard let data = data, error == nil else {
return
}
self.imageView.image = UIImage(data: data)
}
task.resume()
}
} catch {
print("Error -> \(error)")
}
}).resume()
}
i am trying to get news updates from open api through nsurlsession and it has dictionary->array->dictionary->at key "urlToImage"
but iam getting url like http://www.abc.net.au/news/image/8968140-1x1-700x700.jpg but not getting image file in data it was empty can any one minimige the code lenth and solve my problem
Using this piece of code, you can parse that specific URL response successfully, I have tested it in a Playground.
This: "\(String(describing: dataDictionary22["urlToImage"]!))" is not the way get a String from an AnyObject, you should use conditional casting.
if let url = URL(string: "https://newsapi.org/v1/articles?source=abc-news-au&sortBy=top&apiKey=47d2ce48babd47b1bc391b426b89ca23"){
URLSession.shared.dataTask(with: url, completionHandler: { data, response, error in
guard error == nil, let data = data else {
print(error!);return
}
guard let resultJson = (try? JSONSerialization.jsonObject(with: data)) as? [String:Any] else {
return
}
print(resultJson)
guard let articles = resultJson["articles"] as? [[String:Any]], let firstArticle = articles.first else { return }
guard let imageUrlString = firstArticle["urlToImage"] as? String, let imageUrl = URL(string: imageUrlString) else { return }
URLSession.shared.dataTask(with: imageUrl, completionHandler: { data, response, error in
guard error == nil, let data = data else {
print(error!);return
}
let image = UIImage(data: data)
DispatchQueue.main.async {
self.imageView.image = image
}
}).resume()
}).resume()
}
If you want to get all article pictures (in your question you were only parsing the first one), just change guard let articles = resultJson["articles"] as? [[String:Any]], let firstArticle = articles.first else { return } to the following:
for article in articles {
guard let imageUrlString = article["urlToImage"] as? String, let imageUrl = URL(string: imageUrlString) else { return }
URLSession.shared.dataTask(with: imageUrl, completionHandler: { data, response, error in
guard error == nil, let data = data else {
print(error!);return
}
let image = UIImage(data: data)
//use the image
}).resume()
}

data is not coming JSON parsing

let url1 = "https://jsonplaceholder.typicode.com/posts"
var request = URLRequest(url: URL(string: url1)!)
request.httpMethod = "GET"
let urlSession = URLSession.shared
let task = urlSession.dataTask(with: request, completionHandler: {(data,response,error) -> Void in
if let error = error {
print(error)
return
}
if let data = data {
OperationQueue.main.addOperation({ () -> Void in
self.tableView.reloadData()
})
}
})
task.resume()
With or without http method, response data is empty. What am I doing wrong? WiFi works fine. Maybe problem on my simulator settings?
let url = URL(string: "https://jsonplaceholder.typicode.com/posts")
URLSession.shared.dataTask(with:url!, completionHandler: {(data, response, error) in
guard let data = data, error == nil else { return }
do {
let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments)
let posts = json as? [[String: Any]] ?? []
print(posts)
for post in posts{
let product = Product()
product.userId = post["userId"] as! Int
product.id = post["id"] as! Int
product.title = post["title"] as! String
product.body = post["body"] as! String
self.products.append(product)
}
} catch let error as NSError {
print(error)
}
}).resume()
Yeah thanks, but your code is not works too, i mean say data is empty, nothing to be parsed. WiFi on my emulator works fine maybe problem on my xcode8?
Made some changes in your code.
let url = NSURL(string: "https://jsonplaceholder.typicode.com/posts")
NSURLSession.sharedSession().dataTaskWithRequest(NSURLRequest.init(URL: url!), completionHandler: {(data, response, error) in
guard let data = data where error == nil else { return }
do {
let posts = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments)
print(posts)
} catch let error as NSError {
print(error)
}
}).resume()
Output :
Here your all 100 post display

cannot invoke 'jsonObjectWithData'

I cannot figure out how to solve this issue.
This comes from a youtube tutorial to build a simple Weather App.
The tutorial was uploaded in March 2015 and therefor written in a previous version of Swift, there it worked, with the current Swift 2 it doesn't.
The error I get is: "cannot invoke 'jsonObjectWithData' with an argument list of type '(NSData, options: nil, error: NSError)'"
func getWeatherData(urlString:String) {
let url = NSURL(string: urlString)
let task = NSURLSession.sharedSession().dataTaskWithURL(url!){ (data, response, error) in
dispatch_async(dispatch_get_main_queue(), {
self.setLabels(data)
})
}
task.resume()
}
func setLabels(weatherData: NSData) {
var jsonError: NSError
let json = NSJSONSerialization.JSONObjectWithData(weatherData, options: nil, error: jsonError)
if let name = json["name"] as? String {
self.ResultLabel.text = name
}
}
if you want to get this code ready for Swift 2, you have to run the JSONParser with try and catch possible errors.
private func httpGetRequest(request: NSURLRequest!, callback: (NSData?, String?) -> Void) {
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request){
(data, response, error) -> Void in
if error != nil {
callback(nil, error!.localizedDescription)
} else {
callback(data, nil)
}
}
task!.resume()
}
func setLabels(weatherData: NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(weatherData, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
if let name = json["name"] as? String {
self.resultLabel.text = name
}
} catch {
print(error)
self.resultLabel.text = "Lorem Ipsum"
}
}
func loadWeatherData() {
let weatherRequest = NSMutableURLRequest(URL: NSURL(string: "Your URL String goes here")!)
httpGetRequest(weatherRequest){
(data, error) -> Void in
if error != nil {
print("Error: \(error)")
} else {
self.setLabels(data!)
}
}
}
Hope that will help to solve your Problems.
Try this:
var jsonError: NSError?
let json = NSJSONSerialization.JSONObjectWithData(weatherData, options: nil, error: &jsonError)
in swift 3.0 and Swift 4.2
try this ...
do {
let jsonData = try JSONSerialization.data(withJSONObject: your array or dictionary, options: JSONSerialization.WritingOptions()) as Data
let json = try JSONSerialization.jsonObject(with: jsonData as Data, options: JSONSerialization.ReadingOptions(rawValue: UInt(0)))
}
catch
{
}
You need to pass the error pointer into NSJSONSerialization.JSONObjectWithData(...) with &.
let json = NSJSONSerialization.JSONObjectWithData(weatherData, options: nil, error: &jsonError) // &jsonError points to the NSErrorPointer of the NSError object
In swift 3 you can try this:
func setLabels(weatherData: NSData) {
do {
var jsonError: NSError
let json = try JSONSerialization.jsonObject(with: weatherData as Data, options: []) as! NSDictionary
if let name = json["name"] as? String {
self.ResultLabel.text = name
}
} catch {
}
}
In Swift 3, you can fix the same error with the code below:
do{
let jsonData = try JSONSerialization.jsonObject(with: (data)!, options: JSONSerialization.ReadingOptions.mutableContainers) as! [String: AnyObject]
}catch{
print("Error while parsing JSON: Handle it")
}

Resources