Nicholas Lim Nicholas Lim - 5 months ago 32
Swift Question

Unable to append strings to array while parsing JSON data

I am having difficulties storing the results retrieved from a JSON source data. I have confirmed the ability to print the data retrieved but it was not able to store into my local array.

My end objective is to actually print in a UITableView the results.

Below is the code for my relevant table view controller :

import UIKit

class CommunityActivityTableViewController: UITableViewController {
var displayNameArr = [String]()
var postDateArr = [String]()
var postDetailArr = [String]()
var testArr = ["teaad"]

override func viewDidLoad() {
super.viewDidLoad()
parseJson()
print(self.displayNameArr.count) //returns 0
print(self.postDateArr.count) //returns 0
print(self.postDetailArr.count) //returns 0
print(self.testArr.count)
print("end")

}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections

return 1
}

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

// #warning Incomplete implementation, return the number of rows

return self.displayNameArr.count
}



override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("3")
let cell = tableView.dequeueReusableCellWithIdentifier("Cell_activity", forIndexPath: indexPath)



print("hi")
cell.textLabel?.text = "hi"
cell.detailTextLabel?.text = "test"

return cell
}
override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
override func tableView(tableView: UITableView, estimatedHeightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func makeAttributedString(title title: String, subtitle: String) -> NSAttributedString {
let titleAttributes = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleHeadline), NSForegroundColorAttributeName: UIColor.purpleColor()]
let subtitleAttributes = [NSFontAttributeName: UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)]

let titleString = NSMutableAttributedString(string: "\(title)\n", attributes: titleAttributes)
let subtitleString = NSAttributedString(string: subtitle, attributes: subtitleAttributes)

titleString.appendAttributedString(subtitleString)

return titleString
}
func parseJson(){
//MARK: JSON parsing
let requestURL: NSURL = NSURL(string: "<sanitised>")!
let urlRequest: NSMutableURLRequest = NSMutableURLRequest(URL: requestURL)
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) {
print("Everyone is fine, file downloaded successfully.")

do{

let json = try NSJSONSerialization.JSONObjectWithData(data!, options:.AllowFragments)

if let results = json["result"] as? [[String: AnyObject]] {

for result in results {

if let lastname = result["last_name"] as? String {

if let postdate = result["timestamp"] as? String {
if let firstname = result["first_name"] as? String {
if let postdetails = result["post_details"] as? String {

let displayname = firstname + " " + lastname
//print(displayname)
self.displayNameArr.append(displayname)
self.postDateArr.append(postdate)
self.postDetailArr.append(postdetails)
self.testArr.append("haha")


}
}

}

}
}

}

}catch {
print("Error with Json: \(error)")
}

}
}

task.resume()}


}


As per the code above the print results of displaynamearr.count and postDateArr.count and postDetailArr.count returned 0 when it should have returned more than 0 as a result of parseJson() method.

I have printed the display name, postgame and post details variables and they all contain data within so the problem does not lie with the extraction of data but the appending of data into the array.

Appreciate any help provided thanks ! Developed on Xcode 7 and Swift 2.2
Sanitised my JSON source due to sensitive nature of information (i have verified the retrieval of information is OK)

Answer

dataTaskWithRequest() is an asynchronous data loading. It loads on the background thread ensuring your UI won't freeze up. So your array will be empty when you this will be getting executed and hence your error. You need to a completion handler like so:

   func parseJson(completion: (isDone: Bool) -> ()){

///code

for result in results {

                            if let lastname = result["last_name"] as? String {

                                if let postdate = result["timestamp"] as? String {
                                    if let firstname = result["first_name"] as? String {
                                        if let postdetails = result["post_details"] as? String {

                                            let displayname = firstname + " " + lastname
                                            //print(displayname)
                                            self.displayNameArr.append(displayname)
                                            self.postDateArr.append(postdate)
                                            self.postDetailArr.append(postdetails)
  self.testArr.append("haha")


       }
completion(isDone: True)

   }



}

Now in viewDidLoad:

 override func viewDidLoad() {
            super.viewDidLoad()
            parseJson(){ success in
            if success{
            print(self.displayNameArr.count) //returns a value
            print(self.postDateArr.count) //returns a value
            print(self.postDetailArr.count) //returns a value
            print(self.testArr.count) //This wont because I havent added it in the completion handler
            print("end")
       self.tableView.reloadData()
   }
   }
    }