Parse image from web json - ios

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
}

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

Determine when urlsession.shared and Json parsing are finished

I am downloading and then reading a json file. this json contains a list of files and their address on the server.
Everything works fine but I want to get the size of all files to download.
but I have some trouble to set up a completionblock that would indicate that everything is finished.
here is the code.
jsonAnalysis {
self.sum = self.sizeArray.reduce(0, +)
print(self.sum)
} here
func jsonAnalysis(completion: #escaping () -> ()) {
let urlString = "xxxxxxxxxxxxxxxxxxxxx"
let url = URL(string: urlString)
URLSession.shared.dataTask(with:url!) { (data, response, error) in
if error != nil {
print("error")
} else {
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? [String: Any]
self.i = -1
guard let array = json?["Document"] as? [Any] else { return }
for documents in array {
self.i = self.i + 1
guard let VersionDictionary = documents as? [String: Any] else { return }
guard let DocumentName = VersionDictionary["documentname"] as? String else { return }
guard let AddressServer = VersionDictionary["addressserver"] as? String else { return }
self.resultAddressServer.append(AddressServer)
self.addressServer = self.resultAddressServer[self.i]
self.resultDocumentName.append(DocumentName)
self.documentName = self.resultDocumentName[self.i]
let url1 = NSURL(string: AddressServer)
self.getDownloadSize(url: url1! as URL, completion: { (size, error) in
if error != nil {
print("An error occurred when retrieving the download size: \(String(describing: error?.localizedDescription))")
} else {
self.sizeArray.append(size)
print(DocumentName)
print("The download size is \(size).")
}
})
}
} catch {
print("error")
}
}
completion()
} .resume()
}
func getDownloadSize(url: URL, completion: #escaping (Int64, Error?) -> Void) {
let timeoutInterval = 5.0
var request = URLRequest(url: url,
cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: timeoutInterval)
request.httpMethod = "HEAD"
URLSession.shared.dataTask(with: request) { (data, response, error) in
let contentLength = response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
completion(contentLength, error)
}.resume()
}
I would like to get the sum of the array at the end when everything is done, right now print(self.sum) is running before and shows 0.
I am not familiar with the completion and I am sure I am doing everything wrong.
You need DispatchGroup.
Before calling the inner asynchronous task enter, in the completion block of the inner asynchronous task leave the group.
Finally when the group notifies, call completion
let group = DispatchGroup()
for documents in array {
...
let url1 = URL(string: AddressServer) // no NSURL !!!
group.enter()
self.getDownloadSize(url: url1!, completion: { (size, error) in
if error != nil {
print("An error occurred when retrieving the download size: \(String(describing: error?.localizedDescription))")
} else {
self.sizeArray.append(size)
print(DocumentName)
print("The download size is \(size).")
}
group.leave()
})
}
group.notify(queue: DispatchQueue.main) {
completion()
}

Json parsing using URLSession not working

Iam getting an error while i try to send the POST request in swift 3. Any one please suggest me the correct syntax for URLSession.shared method in swift 3. this is what i tried. iam new here.
let task = URLSession.shared.dataTask(with: request, completionHandler: {
(data, response, error) in
if error != nil{
print("error");
return
}
do{
let myjson = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
if let parsejson = myjson{
var msg: String!
msg = parsejson["message"] as! String?
print(msg)
}catch error {
print ("")
}
}
})
task.resume().
Here's working URLSession.shared code. I don't have your URL so I used one that is online, free, and produces JSON:
let someURL = URL(string:"https://jsonplaceholder.typicode.com/posts/2")!
let request = URLRequest(url: someURL)
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
if error != nil {
print("error")
return
}
guard let data = data else {
print("No data")
return
}
do {
if let myjson = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? Dictionary<String,Any> {
if let title = myjson["title"] {
print("Title was \"\(title)\"")
}
}
} catch {
print("Error parsing JSON: \(error)")
}
}
task.resume()
This outputs Title was "qui est esse" for me.

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

Using Data with ContentsOfUrl

I have this code snippet here:
let endpointURL = URL(string: "http://foobar.com")
let downloadTask = URLSession.shared.downloadTask(with: endpointURL!, completionHandler: { url, response, error in
if (error == nil) {
let dataObject = NSData(contentsOfURL: endpointURL!)
let jsonArray: Array = JSONSerialization.JSONObjectWithData(dataObject!, options: nil, error: nil) as Array
}
})
downloadTask.resume()
And I'm having this issue:
Ambiguous use of 'init(contentsOfURL:)' for NSData part
How can I make it unambiguous?
I recommend to use something like this in Swift 3, to load JSON data dataTask is more appropriate than downloadTask.
let endpointURL = URL(string: "http://foobar.com")
let dataTask = URLSession.shared.dataTask(with: endpointURL!) { data, response, error in
guard error == nil else {
print(error!)
return
}
do {
// the assumed result type is `[[String:Any]]` cast it to the expected type
if let jsonArray = try JSONSerialization.jsonObject(with: data!) as? [[String:Any]] {
print(jsonArray)
}
} catch {
print(error)
}
}
dataTask.resume()

Resources