Swift, Json Dictionary<String, AnyObject> send value to label - ios

I have a json who returns me a Dictionary. I can have values inside but I want to use one of this value to put in a label. I have no error but my label inside my view doesn't change.
Here code:
let url = "http://localhost:8888/connexion/"+login!+"/"+password!
let urlString = url.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLQueryAllowedCharacterSet())!
let request = NSURLRequest(URL: NSURL(string: urlString)!)
let alreadyTask = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: { (data, response, error) in
guard let data = data, let _ = response where error == nil else {
print("error")
return
}
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as! Dictionary<String, AnyObject>
print(json)
print(json["3"] as! String)
print(json["4"] as! String)
print(json["5"] as! String)
self.race_label.text = json["3"] as! String
pa_label.text = json["5"] as! String
name_label.text = json["4"] as! String
} catch let error as NSError {
print("json error: \(error.localizedDescription)")
}
})
alreadyTask.resume()
}
And Here log:
["2": blabla12, "1": c#gmail.com, "3": orc, "4": test, "success": 1, "0": 5, "5": 100]
orc
test
100
So, I don't know why it doesn't work. Thank you !

You have to do UI related stuff on the main queue. dataTaskWithRequests calls it's completion handler on a background queue.
To assure your calls are made on the main queue replace:
self.race_label.text = json["3"] as! String
pa_label.text = json["5"] as! String
name_label.text = json["4"] as! String
with:
Swift 2:
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.race_label.text = json["3"] as! String
self.pa_label.text = json["5"] as! String
self.name_label.text = json["4"] as! String
})
Swift3:
DispatchQueue.main.async {
self.race_label.text = json["3"] as! String
self.pa_label.text = json["5"] as! String
self.name_label.text = json["4"] as! String
}

Related

Why URLSession.DataTask.shared is not working properly?

I need to fetch some quizzes for my application from the server. Unfortunately, it seems that URLSession.DataTask.shared is not working. How do I fix the problem?
This is for Swift 4.
import Foundation
import UIKit
class QuizService {
let baseUrl = "https://iosquiz.herokuapp.com/api/quizzes"
func fetchQuizzes(completion: #escaping (([Quiz]?) -> Void)) -> Void {
if let url = URL(string: baseUrl) {
let request = URLRequest(url: url)
let dataTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
if let resultsList = json as? [String: Any], let results = resultsList["quizzes"] as? [[String: Any]] {
let quizzes = results.map({ json -> Quiz? in
print(json)
if
let title = json["title"] as? String,
let id = json["id"] as? Int,
let level = json["level"] as? Int,
let description = json["description"] as? String,
let category = json["category"] as? String,
let questions = json["questions"] as? [String: Any],
let imageUrl = json["image"] as? String {
let quiz=Quiz(id:id,title:title,descript:description,category:category,level:level,imageUrl:imageUrl,questions:questions)
return quiz
} else {
return nil
}
}).filter { $0 != nil } .map { $0! }
completion(quizzes)
} else {
completion(nil)
}
} catch {
completion(nil)
}
} else {
completion(nil)
}
}
dataTask.resume()
} else {
completion(nil)
}
}
}
My error is that field of quizzes are null, so my code is not working in my view controller.
I took a look at the response here https://iosquiz.herokuapp.com/api/quizzes.
The "questions" should be array of dictionaries instead of dictionary.
so it should works if you replace this line
let questions = json["questions"] as? [String: Any]
with this line
let questions = json["questions"] as? [[String: Any]]
BTW, I prefer to extract the logic of parsing json into another method to keep fetchQuizzes method simple.
Hope this helps!

How to append the data from the JSON

How to append the data ?
my api as:-
[
{
"Name": "Vegetables",
"PictureModel": {
"ImageUrl": "http://example.jpeg"
}
},
{
"Name": "Fruits",
"PictureModel": {
"ImageUrl": "http://example1.jpeg"
}
}
]
for fetching the data from json
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as! Array<[String:Any]>
print(json)
let type = json[0]
let name = type["Name"] as! String
let PictureModel = type["PictureModel"] as! [String:Any]
print(PictureModel)
let nameofimage = PictureModel["ImageUrl"] as! String
print(nameofimage)
self.fetchedHome.append(Categories(name: name, images: nameofimage))
self.tableview.reloadData()
} catch {
print(error)
}
}
}.resume()
And i got the output in the tableview .In tableview i got first data as name-vegetable and image in UIImageview.
.But second data not display .So how to append ? how to give for loop and append
Use this code you will get one by one object in For loop:-
if let data = json as? NSArray {
for data in data {
if let data = data as? [String: AnyObject] {
//Here you will get data
print("Name", data["Name"])
}
}
}
Are you getting JSON correctly in print(json)?
If yes, then you should try looping on "json" as follows :-
for (var keyAttr in json) {
let dataRow = json[keyAttr]
}
Inside the dataRow you can get "Name" and "PictureModel".
I am hoping that it should work.
All the best.
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: []) as! Array<[String:Any]>
if let data = json as? [String:Any] {
for data in data {
let name = data["Name"] as! String
let PictureModel = data["PictureModel"] as! [String:Any]
print(PictureModel)
let nameofimage = PictureModel["ImageUrl"] as! String
print(nameofimage)
self.fetchedHome.append(Categories(name: name, images: nameofimage))
}
}
self.tableview.reloadData()
} catch {
print(error)
}
}
}.resume()

Working with JSON data retrieving into Swift data types

I'm trying to get data from a URL. It was successful. I can download and convert to a dictionary[String : Any] but response is in nested loops. I don't to how to retrieve. Can someone suggest how to get text and value in the response?
func getDataFromUrl() {
let url = URL(string: "https://maps.googleapis.com/maps/api/distancematrix/json?units=imperial&departure_time=1408046331&origins=37.407585,-122.145287&destinations=37.482890,-122.150235")
let request = NSMutableURLRequest(url: url!)
let session = URLSession.shared
request.httpMethod = "GET"
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any]
let destinationAddress = jsonData!["destination_addresses"]
print("Destination address \(String(describing: destinationAddress!))")
let origin_addresses = jsonData!["origin_addresses"]
print("Origin_addresses \(String(describing: origin_addresses!))")
let rows = jsonData!["rows"]
print("Rows \(String(describing: rows!))")
// Here I want to print text and value.
} catch {
// handle error
}
})
dataTask.resume()
}
The above answers work, but in my opinion the more swiftier approach is to use Codable.
class MyResponseType:Codable {
let destination_addresses:String
let rows:[MyCustomRowData]
}
class MyCustomRowData:Codable {
let elements:[MyCustomElementsData]
}
class MyCustomElementsData:Codable {
// properties here
}
Doing this, parsing the json is done like this:
let response = try? JSONDecoder().decode(MyResponseType.self, from: data)
Where the data variable is just the retrieved Data object from the request.
Initially you have to set up some boilerplate code to replicate your expected data format, but working with it is really worth it (and it makes it highly testable).
When the decode succeeds you have a perfectly typed object, it can also have optionals. It just wont decode if fields are missing or of the wrong type (which is a good thing).
Here is the way you can parse text and Value from response:
do{
if let jsonData = try JSONSerialization.jsonObject(with: data!, options: JSONSerialization.ReadingOptions.mutableContainers) as? [String: Any] {
if let destinationAddress = jsonData["destination_addresses"] as? [String] {
print(destinationAddress) //["1 Hacker Way, Menlo Park, CA 94025, USA"]
}
if let origin_addresses = jsonData["origin_addresses"] as? [String] {
print(origin_addresses) //["3251 Hillview Ave, Palo Alto, CA 94304, USA"]
}
if let rows = jsonData["rows"] as? [[String: AnyObject]] {
if rows.indices.contains(0) {
if let elements = rows[0]["elements"] as? [[String: AnyObject]] {
for element in elements {
if let duration = element["duration"] as? [String: AnyObject] {
let text = duration["text"] as? String ?? ""
print(text) //17 mins
let value = duration["value"] as? Int ?? 0
print(value) //1010
}
if let distance = element["distance"] as? [String: AnyObject] {
let text = distance["text"] as? String ?? ""
print(text) //7.2 mi
let value = distance["value"] as? Int ?? 0
print(value) //11555
}
}
}
}
}
}
}catch{ //error handle
}
Use this code:
let rows = jsonData["rows"] as! Array
let element = rows[0] as! Dictionary
let elementArray = element.value(forKey: "elements")
let distance = elementArray[0].value(forKey: "distance")
let text = distance.value(forKey: "text")
print(text)
let value = distance.value(forKey: "value")
print(value)

JSON Parsing & Optionals in Swift 3

So i recently updated to Swift 3/XCode 8 and some of my code went hay-wire. I've read that some syntax changes have been made but I can't seem get this one right.
I make a request to Twitter and get JSON back:
func forLoadStats(completion: (AnyObject?, NSError?) -> Void)
{
var clientError: NSError?
let idString = api.getUserID()
let client = TWTRAPIClient()
let request = client.urlRequest(withMethod: "GET", url: "https://api.twitter.com/1.1/users/show.json", parameters: ["user_id" : 27446437], error: &clientError)
client.sendTwitterRequest(request)
{ (response, data, connectionError) in
if (connectionError == nil)
{
do {
if let json: Any = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [AnyObject]
{
if let json = json, let immage = json?["profile_image_url_https"] as? String
{
//Make ProfilePic edges round
self.profPic.layer.cornerRadius = 42
self.profPic.clipsToBounds = true
//let immage = image["profile_image_url_https"] as String
let _vImageUrl = immage.replacingOccurrences(of: "_normal", with: "")
let urlProfilePic = NSURL(string: _vImageUrl)
let urlPP = NSData(contentsOf: urlProfilePic! as URL)
self.profPic.image = UIImage(data: urlPP! as Data)
let ScrName = json["screen_name"] as! String
self.scrNameLabel.text = "#\(ScrName)"
//Populate Followers Label.text
let flwrVar = json["followers_count"] as! Int
self.followerLbl.text = "\(flwrVar)"
//Populate Following Label.text
let flwngVar = json["friends_count"] as! Int
self.followingLbl.text = "\(flwngVar)"
//Populate Bio
let bio = json["description"] as! String
self.bioLabel.text = "\(bio)"
//created at date
let accountAge = json["created_at"] as! String
self.createdLbl.text = "\(accountAge)"
let tweetCount = json["statuses_count"] as! Int
self.tweetCount.text = "\(tweetCount)"
let likes = json["favourites_count"] as! Int
self.likesCount.text = "\(likes)"
let lists = json["listed_count"] as! Int
self.listedCount.text = "\(lists)"
}
}
}
catch let error
{
print(error)
}
}
}
}
I get an error on the second "If let" statement that says: "initializer for conditional binding must have optional type not 'Any.
Can someone explain why this is?
Your JSON is obviously a dictionary, a JSON dictionary in Swift 3 is [String:Any]
You caused the error by the silly Any annotation (which is supposed to be Any? but is practically nonsensical) because it confuses the compiler.
If you use a do block, try without question mark but use optional binding:
...
if let json = try JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any] {
if let immage = json["profile_image_url_https"] as? String { ...
There are a couple of problems with the syntax. [AnyObject] will not work to use reference items such as json["profile_image_url_https"]. also, you are redeclaring json through let json = json, which makes it a non option in your let immage = json?["profile_image_url_https"] call, so that becomes a problem. This structure does not have any compiler errors
if let json = try? JSONSerialization.jsonObject(with: data!, options: .allowFragments) as? [String:Any]
{
if let json = json, let immage = json["profile_image_url_https"] as? String
{
}
}
This does not have any compiler errors.

Swift error in converting nsdata to NSDictionary

I'm trying to get JSON Array from a web service and I keep getting an error, and I spent much time on this but I can't figure it out.
http://ashishkakkad.com/2014/10/update-json-array-parsing-in-swift-langauage-ios-8-xcode-6-gm/
my Code
if let url=NSURL(string:"http://www.example.com/service/service.php?get=6"){
print(url)
if let allContactsData=NSData(contentsOfURL:url){
if let string1 = NSString(data: allContactsData, encoding: NSUTF8StringEncoding){
print(string1)
}
do{
if let allContacts: AnyObject = try NSJSONSerialization.JSONObjectWithData(allContactsData, options:NSJSONReadingOptions.MutableContainers) as! NSDictionary{
if let json = allContacts as? Array<NSObject> {
print(json)
for index in 0...json.count-1 {
let contact : NSObject? = json[index]
print(contact)
let collection = contact! as! Dictionary<String, AnyObject>
print(collection)
print(collection["title"])
let name : AnyObject? = collection["title"]
let cont : AnyObject? = collection["link"]
self.names.append(name as! String)
self.contacts.append(cont as! String)
}
}
print(self.names)
print(self.contacts)
}
} catch {
print("Dim background error")
}
}
the error I get on this line
if let allContacts: AnyObject = try
NSJSONSerialization.JSONObjectWithData(allContactsData,
options:NSJSONReadingOptions.MutableContainers) as! NSDictionary
You should be casting to [[String: AnyObject]] rather than NSDictionary. However, I admit that I'm not familiar with the approach you're attempting to use, I would do something more like this:
enum HTTPStatusCodes : Int {
case Ok = 200
case Created = 201
case BadRequest = 404
}
let request = NSMutableURLRequest(URL: NSURL(string: "http://www.example.com/service/service.php?get=6")!)
let session = NSURLSession.sharedSession()
request.HTTPMethod = "GET"
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
guard let testResponse = response as? NSHTTPURLResponse else {
print("bad \(response)")
return
}
guard let status = HTTPStatusCodes(rawValue: testResponse.statusCode) else {
print("derpped gain")
return
}
print(status)
switch status {
case .Created:
print("ehem")
case .BadRequest:
print("bad request")
case .Ok:
print("ok")
let headerFields = testResponse.allHeaderFields
guard let returnedData = data else {
print("no data was returned")
break
}
do {
// convert data to string
let jsonObject = try NSJSONSerialization.JSONObjectWithData(returnedData, options: .MutableLeaves) as! [[String:AnyObject]]
//print(jsonDict)
} catch let error {
print(error)
}
// update user interface
dispatch_sync(dispatch_get_main_queue()) {
print("update interface")
}
}
}
task.resume()

Resources