Hi,
I'm trying to parse data on to the listview and am able to get it and
display it on the tableView but the problem is it is taking hell lot
of time to display it on the tableview. Please find the my code below.
func jsonParsing()
{
activityIndicatorView.startAnimating()
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest (URL: deviceListURL)
request.HTTPMethod = "GET"
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if error != nil {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
if(data != nil) {
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as! NSMutableArray
//println("Data: \(jsonResult)")
var dataDict: NSDictionary
for dataDict : AnyObject in jsonResult {
var device_id: NSString = dataDict.objectForKey("deviceId") as! NSString
var device_name: NSString = dataDict.objectForKey("deviceName") as! NSString
var device_status: NSInteger = dataDict.objectForKey("status") as! NSInteger
let dictionary = [self.deviceID: device_id, self.deviceName: device_name, self.Status: device_status]
self.myObject.addObject(dictionary)
}
println("My object = %#", self.myObject)
println(self.myObject.count)
if self.myObject.count != 0 {
self.reloadTable()
}
}
if err != nil {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
})
task.resume()
}
The completion handler is running in a background queue, not the main thread. UI updates have to happen on the main thread, though.
Try calling reloadTable() on the main thread:
dispatch_sync(dispatch_get_main_queue(), {
self.reloadTable()
})
(I just typed this in here untested, so I hope it works this way)
Related
When I try to run this project I am greeted with a "Use of unresolved identifier error." Here is the code I get the error on the line with
var jsonDict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers)
as! NSDictionary
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
if((error) != nil) {
print(error!.localizedDescription)
} else {
let err: NSError?
do {
var jsonDict = try NSJSONSerialization.JSONObjectWithData(data!, options: NSJSONReadingOptions.MutableContainers) as! NSDictionary
} catch {
if(err != nil) {
print("JSON Error \(err!.localizedDescription)")
}
else {
//5: Extract the Quotes and Values and send them inside a NSNotification
let quotes:NSArray = ((jsonDict.objectForKey("query") as! NSDictionary).objectForKey("results") as! NSDictionary).objectForKey("quote") as! NSArray
dispatch_async(dispatch_get_main_queue(), {
NSNotificationCenter.defaultCenter().postNotificationName(kNotificationStocksUpdated, object: nil, userInfo: [kNotificationStocksUpdated:quotes])
})
}
}
}
})
can someone please help. Thank you.
You problem could be this line of code in the catch block.
let quotes:NSArray = ((jsonDict.objectForKey("query") as! NSDictionary).objectForKey("results") as! NSDictionary).objectForKey("quote") as! NSArray
In the above statement jsonDict is out of scope. You declared jsonDict in the do block but are trying to use it in the catch block.
Try Following:-
(Assuming JSON has a root node structure)
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: yourURL)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(urlRequest) {
(data, response, error) -> Void in
let httpResponse = response as! NSHTTPURLResponse
let statusCode = httpResponse.statusCode
if (statusCode == 200) {
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)
if let queries = json["query"] as? [[String: AnyObject]] {
for query in queries {
if let quote = query["quote"] as? String {
self.quoteArr.append(quote)
}
}//for loop
dispatch_async(dispatch_get_main_queue(),{
// your main queue code
NSNotificationCenter.defaultCenter().postNotificationName(kNotificationStocksUpdated, object: nil, userInfo: [kNotificationStocksUpdated:quotes])
})//dispatch
}// if loop
}
catch
{
print("Error with Json: \(error)")
}
}
else
{
// No internet connection
// Alert view controller
// Alert action style default
}
this cobweb of code is exactly why SwiftyJSON library exists. I recommend it highly, it can be imported into your project using cocoapods.
using this library the resultant code would be
jsonQuery["query"]["results"]["quote"]
which is more readable and as you implement more APIs, much faster.
Before i start, i have went through each and every question relating to this issue. didnt help.
I want to refresh the json contents of my tableView which are fetched from a website.
The URL for each category comes from a different file that has All the categories listed in it.
The code that fetches the content is this
func animalSelected(animal: Animal) {
var request: NSURLRequest = NSURLRequest(URL: animal.url!)
self.refresh(animal.url!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(animal.url!, completionHandler: {data, response, error -> Void in
// println("Task completed")
if(error != nil) {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err != nil) {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
let results: NSArray = jsonResult["posts"] as NSArray
self.didReceiveResults(jsonResult)
})
task.resume()
delegate?.collapseSidePanels?()
}
func didReceiveResults(results: NSDictionary) {
var resultsArr: NSArray = results["posts"] as NSArray
dispatch_async(dispatch_get_main_queue(), {
self.tableData = resultsArr
self.tableView.reloadData()
})
}
My ViewDidLoad method and the refresh method is as shown below
override func viewDidLoad() {
super.viewDidLoad()
refresher = UIRefreshControl()
refresher.attributedTitle = NSAttributedString(string: "Pull to Refresh")
refresher!.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refresher)
}
func refresh(categoryUrl : NSURL) {
var request: NSURLRequest = NSURLRequest(URL: categoryUrl)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(categoryUrl, completionHandler: {data, response, error -> Void in
if(error != nil) {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err != nil) {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
let results: NSArray = jsonResult["posts"] as NSArray
self.didReceiveResults(jsonResult)
})
task.resume()
self.refresher.endRefreshing()
}
I need to refresh the contents of the same URL that has been selected i.e refresh the same category.
I get this error : [UIRefreshControl absoluteURL]: unrecognized selector sent to instance 0x7fa0b3d73750
I think it is something related to absoluteURL. Bt don't know what is it..
plsss plssssss plssss help
You're trying to get the absoluteURL of a UIRefreshControl that you think is actually an NSURL.
To be exact, your sender in refresh(categoryUrl: NSURL) is the UIRefreshControl not NSURL.
I'm trying hard to learn IOS development.
I have followed this guide and successfully managed to create a working quiz game. The last couple of days I have been trying to connect the game to an external database. Finally after many hours I'm able to read from MYSQL using JSON parsing.
Right now Im struggling with a way to convert the json array into a normal array.
My current hardcoded questions look like this:
let questionOne = questionTemplate("the first question?", answerOne: "a answer", answerTwo: "a second answer", answerThree: "a third aswer", answerFour: "tast possible answer", correctAnswer: 2)
Then they are added to an array
spormslaArray = [questionOne, questionTwo, questionThree, questionFour, questionFive, questionSix,questionSeven]
Then im doing some more loading of answers and questions before i add them to the GUI based on an array counter from the first to the last question.
func questionTemplate(question:String, answerOne:String, answerTwo:String, answerThree:String, answerFour:String, correctAnswer:Int) -> NSArray {
//Set the question
var quizQuestion = question
//set the answers and the right answer
var firstAnswer = answerOne
var secondAnswer = answerTwo
var thirdAnswer = answerThree
var fourthAnswer = answerFour
var rightAnswer = correctAnswer
var gjennverendeSporsmal = 1
//Add all the questions and answers to an array
let questionAnswerArray = [question, firstAnswer, secondAnswer, thirdAnswer, fourthAnswer, rightAnswer]
return questionAnswerArray
}
I now want to add questions from my database into spormslaArray.I got questions loaded into xcode using this code:
func lasteJson(){
let urlPath = "http://universellutvikling.no/utvikling/json.php"
let url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
if error != nil {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if err != nil {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
let json = JSON(jsonResult)
let count: Int? = json["data"].array?.count
// println("found \(count!) challenges")
//Im just setting a hardcoded number, it will be based on the array when I have figured that out
var tall = 7
let ct = count
for index in 0...tall-1 {
println(json["data"][index] )
//DEtte printer ut induviduelt
/*
if let questionId = json["data"][index]["id"].string {
println(questionId)
}
if let spm1 = json["data"][index]["answerOne"].string {
println(spm1)
}
if let spm2 = json["data"][index]["answerTwo"].string {
println(spm2)
}
if let spm3 = json["data"][index]["answerThree"].string {
println(spm3)
}
if let spm4 = json["data"][index]["answerFour"].string {
println(spm4)
}
if let correctAnswer = json["data"][index]["correctAnswer"].string {
println(correctAnswer)
}
*/
}
//}
})
task.resume()
This is mostly based on this code.
If Im ignoring the fact that Im getting some breakpoints when im running the app, and that nordic characters in my database makes the ios simulator crash; This is the parsing result in the command line:
{
"correctAnswer" : "1",
"id" : "0",
"answerThree" : "aa3",
"answerFour" : "aa4",
"questionTemplate" : "sporsmal",
"answerOne" : "as1",
"answerTwo" : "aa2"
}
//////Finally here is the problem///////
I have tried for hours to make a variable from the json array, into the guestion array.
I want to do something like this:
let questionOne = json["data"][index]["answerOne"].string
and then add them to an array
let questionArray[questionOne, QuestionTwo.. etc]
I have tried for hours without any progress, so my last hope is you guys! :-)
Use this...
To post JSON or to receive JSON (Leave dictionary nil to GET)
///Use completion handler to handle recieved data
func sendJSON(params:Dictionary<String, String>?, toAdressOnServer:String, customCompletionHandler:((parsedData:AnyObject?, statusCode: Int) -> Void)?){
var request = NSMutableURLRequest(URL: NSURL(string: SERVER_NAME + toAdressOnServer)!)
var session = NSURLSession.sharedSession()
var err: NSError?
if (params == nil){
request.HTTPMethod = "GET"
}else{
request.HTTPMethod = "POST"
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(params!, options: nil, error: &err)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err: NSError?
var json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments , error: &err)
// Did the JSONObjectWithData constructor return an error? If so, log the error to the console
if(err != nil) {
println(err!.localizedDescription)
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: '\(jsonStr)'")
customCompletionHandler?(parsedData: json, statusCode: -1)
}
else {
// The JSONObjectWithData constructor didn't return an error. But, we should still
// check and make sure that json has a value using optional binding.
if let parseJSON: AnyObject = json {
// Okay, the parsedJSON is here, let's get the value for 'success' out of it
// Use keyword "success" in JSON from server to register successful transmission
let success = parseJSON["success"] as? Int
if (success == nil){
customCompletionHandler?(parsedData: json, statusCode: -2)
}else{
customCompletionHandler?(parsedData: json, statusCode: success!)
}
}
else {
// The json object was nil, something went worng. Maybe the server isn't running?
let jsonStr = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Error could not parse JSON: \(jsonStr)")
customCompletionHandler?(parsedData: json, statusCode: -1)
}
}
})
task.resume()
}
And To decode the JSON in your case the array, but it can have any form.
self.sendJSON(nil, toAdressOnServer: "ADRESS", customCompletionHandler: { (parsedData, statusCode) -> Void in
//check for valid data
if (parsedData != nil){
//Loop through results
for (var x = 0; x < parsedData!.count; x++){
///primary key of the item from the internet
let pk:Int = (parsedData![x] as NSDictionary).objectForKey("pk") as Int
let month = ((parsedData![x] as NSDictionary).objectForKey("fields") as NSDictionary).objectForKey("month")! as String
let quote = ((parsedData![x] as NSDictionary).objectForKey("fields") as NSDictionary).objectForKey("quote")! as String
let quotee = ((parsedData![x] as NSDictionary).objectForKey("fields") as NSDictionary).objectForKey("quotee")! as String
})
This is an example, use parsed data as "json" and use it with the appropriate structure. In this case the JSON was An array of some dictionary with a fields dictionary that has another dictionary with more fields. So you can have any JSON structure.
I Hope this helps!
It seems that you almost have the answer there. I think what you are missing is questionArray.append(... in your loop to build your array. You could also make things easier for yourself if you modified your JSON so that the questions were in an array rather than discrete keys and change your questionTemplate to take an array rather than discrete answers.
Working with what you have however -
func lasteJson(){
let urlPath = "http://universellutvikling.no/utvikling/json.php"
let url: NSURL = NSURL(string: urlPath)!
let session = NSURLSession.sharedSession()
questionsArray=[Question]()
let task = session.dataTaskWithURL(url, completionHandler: { (data, response, error) -> Void in
if error != nil {
// If there is an error in the web request, print it to the console
println(error.localizedDescription)
}
else {
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if err != nil {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
else {
let questions=jsonResult["data"] as? [[String:String]]
if (questions != nil) {
for question in questions! {
let answer1=question["answerOne"]!
let answer2=question["answerTwo"]!
let answer3=question["answerThree"]!
let answer4=question["answerFour"]!
let id=question["id"]!
let questionTemplate=question["questionTemplate"]!
let correctAnswer=question["correctAnswer"]!
let newQuestion=Question(questionTemplate, answerOne: answer1, answerTwo:answer2, answerThree: answer3, answerFour: answer4, correctAnswer: correctAnswer)
questionsArray.append(newQuestion)
}
}
}
}
})
task.resume()
}
You don't show your questionTemplate, but I am not sure why/how it returns an array. My code above assumes that there is a class Question and fills in a property questionsArray
I am new to iOS development and need help on below issue.
I have the below code that downloads a JSON data from web and populates an array with that.
let urlPath = "……………………………"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(url!, completionHandler: {data, response, error -> Void in
if (error != nil) {
println(error)
} else {
let jsonResult: AnyObject = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil)!
dispatch_async(dispatch_get_main_queue()) {
for var i = 0; i < jsonResult.count; i++ {
self.sales[i] = jsonResult[i]["daily_sales"] as NSString
}
}
}
})
task.resume()
println(self.sales[0])
at the end the app crashes since it does not wait for the JSON data to be downloaded.
What are the alternative ways to handle this?
It crashes because of this println(self.sales[0]). You trying to display sales that are not even downloaded. Put this line at the end of your completion block and you should be OK
I'm trying to make a request to a server, which should return data that I can use in the rest of my application. Here is my code:
func makeNewUser() -> NSDictionary {
var full_url = getFullUrl("makeNewUser")
var toReturn: NSDictionary = NSDictionary()
var request: NSURLRequest = NSURLRequest(URL:full_url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession.sharedSession()
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
println(response)
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err != nil) {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
toReturn = jsonResult
});
task.resume()
self.delegate?.didReceiveAPIResults(toReturn)
println(toReturn)
return toReturn
}
I am sending toReturn data to a delegate function in the caller, but it is not available. I believe the reason for this is because the request is asynchronous. What is the proper way for me to handle this so that the caller knows to wait for this data before continuing?
move the delegate call into the session completion block:
func makeNewUser() {
var full_url = getFullUrl("makeNewUser")
var toReturn: NSDictionary = NSDictionary()
var request: NSURLRequest = NSURLRequest(URL:full_url)
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let session = NSURLSession.sharedSession()
let task : NSURLSessionDataTask = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
println(response)
var err: NSError?
var jsonResult = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err) as NSDictionary
if(err != nil) {
// If there is an error parsing JSON, print it to the console
println("JSON Error \(err!.localizedDescription)")
}
self.delegate?.didReceiveAPIResults(jsonResult) // <<-----
});
task.resume()
}
And you just have to be aware that the result is not immediately available. You don't want to block the function (and UI) on long running operations like network requests anyway.