I have async request to HTTP, i want to read JSON and fill my viewtable.
I get data with request, i make NSArray, but i can pass it inside my functions, tableView numberOfRowsInSection return only 1, please help.
import Foundation
import UIKit
class ThirdView : UITableViewController {
var jsonz:NSArray = ["Ray Wenderlich"];
let url = NSURL(string: "http://iweddings.ru/xmlrestaurant.json");
override func viewDidLoad() {
super.viewDidLoad()
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
let json = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as! NSArray
println(json)
// here i see in xCode output
// price = 4500;
// rating = 45;
// slogan = "\U041d\U0435\U043b\U0435\U0433\U0430\U043b\U044c\U043d\U043e";
// status = 1;
// type = 1;
// etc....
self.jsonz = json;
}
task.resume()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println(self.jsonz.count);
return self.jsonz.count;
// here i see always "1" ???? why?
}
NSArray jsonz does not change.
Sorry for my english.
You need to call reloadData() method after json data is downloaded:
class ThirdView: UITableViewController {
var jsonz: NSArray = ["Ray Wenderlich"]
let url = NSURL(string: "http://iweddings.ru/xmlrestaurant.json")
override func viewDidLoad() {
super.viewDidLoad()
let task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, error) in
let json = NSJSONSerialization.JSONObjectWithData(data!, options: nil, error: nil) as! NSArray
println(json)
self.jsonz = json;
self.tableView.reloadData()
}
task.resume()
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println(self.jsonz.count);
return self.jsonz.count;
}
}
Related
I create a request to CocktailDB API and get cocktails' categories from JSON output, then I add all cocktails' categories to an array.
I want to display elements from an array in my tableview.
But tableview is empty and categoriesArray.count return 0.
My code:
class ViewController: UIViewController {
struct Categories {
let categoryName: String
}
#IBOutlet weak var tableView: UITableView!
var categoriesArray = [String]()
override func viewDidLoad() {
super.viewDidLoad()
getCategories()
}
func getCategories() {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")!
let session = URLSession.shared
let task = session.dataTask(with: url) { (data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
let output = self.jsonParserCategories(jsonData!)
self.categoriesArray.append(contentsOf: output)
print(self.categoriesArray) // print out an array of categories
} catch {
print(error)
return
}
}
task.resume()
}
private func jsonParserCategories(_ data: [String: Any]) -> [String] {
var categArray: [String] = []
let allDrinks = data["drinks"] as! [Any]
allDrinks.forEach {
categArray.append(($0 as! [String: Any])["strCategory"] as! String)
}
return categArray
}
}
extension ViewController: UITableViewDelegate, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell(style: .default, reuseIdentifier: "cell")
}
func numberOfSections(in tableView: UITableView) -> Int {
return categoriesArray.count // return 0
}
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
return categoriesArray[section]
}
}
JSON structure:
Reload your table data once you get response
func getCategories() {
let url = URL(string: "https://www.thecocktaildb.com/api/json/v1/1/list.php?c=list")!
let session = URLSession.shared
let task = session.dataTask(with: url) { (data, response, error) in
do {
let jsonData = try JSONSerialization.jsonObject(with: data!, options: []) as? [String: Any]
let output = self.jsonParserCategories(jsonData!)
self.categoriesArray.append(contentsOf: output)
print(self.categoriesArray) // print out an array of categories
DispatchQueue.main.async {
tableView.reloadData()
}
} catch {
print(error)
return
}
}
task.resume()
}
You've to call reloadData after the data is set. Also, set the array to empty at the beginning of the getCategories method.
func getCategories() {
categoriesArray = [] // set array to empty
//...
self.categoriesArray.append(contentsOf: output)
DispatchQueue.main.async {
self.tableView.reloadData() // call reload once `categoriesArray` is set
}
Add-on: Use Codable model to decode JSON instead of JSONSerialization.
I'm creating an app for iOS that get data from my server with json and store it on a tableview; with this no problems, my data are simple notes, some notes are linked together forming projects (simple dependency_id on my database sql), my question is: How can i group my notes by project, like a contact list? (ex. http://img.wonderhowto.com/img/13/66/63535060544981/0/siri-exploit-you-could-bypass-iphones-lock-screen-call-message-any-contact-ios-7-1-1.w654.jpg)
This is the source that populate the table with all notes:
//
// TableController.swift
// uitableview_load_data_from_json
import UIKit
class TableController: UITableViewController {
var TableData:Array< String > = Array < String >()
var userid = NSUserDefaults.standardUserDefaults().stringForKey("userid")!
override func viewDidLoad() {
super.viewDidLoad()
get_data_from_url("http:/localhost/index.php/iOS_getNomenTasks?n=" + userid)
}
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return TableData.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as UITableViewCell
cell.textLabel?.text = TableData[indexPath.row]
return cell
}
func get_data_from_url(url:String)
{
let httpMethod = "GET"
let timeout = 15
let url = NSURL(string: url)
let urlRequest = NSMutableURLRequest(URL: url!,
cachePolicy: .ReloadIgnoringLocalAndRemoteCacheData,
timeoutInterval: 15.0)
let queue = NSOperationQueue()
NSURLConnection.sendAsynchronousRequest(
urlRequest,
queue: queue,
completionHandler: {(response: NSURLResponse!,
data: NSData!,
error: NSError!) in
if data.length > 0 && error == nil{
let json = NSString(data: data, encoding: NSASCIIStringEncoding)
self.extract_json(json!)
}else if data.length == 0 && error == nil{
println("Nothing was downloaded")
} else if error != nil{
println("Error happened = \(error)")
}
}
)
}
func extract_json(data:NSString)
{
var parseError: NSError?
let jsonData:NSData = data.dataUsingEncoding(NSASCIIStringEncoding)!
let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(jsonData, options: nil, error: &parseError)
if (parseError == nil)
{
if let task_list = json as? NSArray
{
for (var i = 0; i < task_list.count ; i++ )
{
if let tasj_obj = task_list[i] as? NSDictionary
{
if let task_id = tasj_obj["id"] as? String
{
if let task_name = tasj_obj["tk_title"] as? String
{
if let task_type = tasj_obj["tk_type"] as? String
{
TableData.append(task_name)
}
}
}
}
}
}
}
do_table_refresh();
}
func do_table_refresh()
{
dispatch_async(dispatch_get_main_queue(), {
self.tableView.reloadData()
return
})
}
}
ok..
task_id is the note id,
task_name is the note name,
task_type is the value that identify if note is a project or not, if task_type is 0, the note is a simple note, if task_type is 1 the note is a project.
If you create an UITableViewController, you have the function :
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
With it, you have 3 sections who contains 2 lines :
var tab: [String] = ["section 1", "section 2", "section 3"]
var tabData: [AnyObject] = [["item1", "item2"],["item1", "item2"],["item1", "item2"]]
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return tab.count
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.dataTab[section].count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell: UITableViewCell = UITableViewCell()
return cell
}
I have managed to retrieve data from JSON using swiftJSON but I am facing problems when i try to populate tableview. I am new to iOS development, so please bear with me on this. I would appreciate if you could help or provide some ideas ?
Here's the code:
override func viewDidLoad(){
super.viewDidLoad()
getContactListJSON()
}
func getContactListJSON(){
let urlString = "http://jsonplaceholder.typicode.com/users"
let urlEncodedString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let url = NSURL( string: urlEncodedString!)
var task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, innerError) in
let json = JSON(data: data)
let contactsArray = json.arrayValue
dispatch_async(dispatch_get_main_queue(), {
for contacts in contactsArray
{
let id = contacts["id"].stringValue
let name = contacts["name"].stringValue
println( "id: \(id) name: \(name)" )
}
})
}
task.resume()
}
Here is your complete code for that:
import UIKit
class TableViewController: UITableViewController {
var tableName = [String]()
var tableID = [String]()
override func viewDidLoad() {
super.viewDidLoad()
getContactListJSON()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func getContactListJSON(){
let urlString = "http://jsonplaceholder.typicode.com/users"
let urlEncodedString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let url = NSURL( string: urlEncodedString!)
var task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, innerError) in
let json = JSON(data: data)
let contactsArray = json.arrayValue
dispatch_async(dispatch_get_main_queue(), {
for contacts in contactsArray
{
let id = contacts["id"].stringValue
let name = contacts["name"].stringValue
println( "id: \(id) name: \(name)" )
self.tableName.append(name)
self.tableID.append(id)
}
dispatch_async(dispatch_get_main_queue(),{
self.tableView.reloadData()
})
})
}
task.resume()
}
// MARK: - Table view data source
override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableName.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as! TableViewCell
// Configure the cell...
cell.id.text = tableID[indexPath.row]
cell.name.text = tableName[indexPath.row]
return cell
}
}
And HERE is working sample project for you with custom cell.
First declare a local variable NSArray called contactsArray.
override func viewDidLoad(){
super.viewDidLoad()
getContactListJSON()
}
//Code for downloading data
func getContactListJSON(){
let urlString = "http://jsonplaceholder.typicode.com/users"
let urlEncodedString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let url = NSURL( string: urlEncodedString!)
var task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, innerError) in
let json = JSON(data: data)
self.contactsArray = json.arrayValue
dispatch_async(dispatch_get_main_queue(), {
[self.tableView reloadData]
})
}
task.resume()
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.contactsArray.count;
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell:UITableViewCell = self.tableView.dequeueReusableCellWithIdentifier("cell") as UITableViewCell
var contacts:NSDictionary = self.contactsArray[indexPath.row];
cell.textLabel?.text = contacts["name"].stringValue
//.......
//.......
return cell
}
Here is a piece of code.
var dataArray = [String]()
override func viewDidLoad(){
super.viewDidLoad()
getContactListJSON()
}
func getContactListJSON(){
let urlString = "http://jsonplaceholder.typicode.com/users"
let urlEncodedString = urlString.stringByAddingPercentEscapesUsingEncoding(NSUTF8StringEncoding)
let url = NSURL( string: urlEncodedString!)
var task = NSURLSession.sharedSession().dataTaskWithURL(url!) {(data, response, innerError) in
let json = JSON(data: data)
let contactsArray = json.arrayValue
dispatch_async(dispatch_get_main_queue(), {
for contacts in contactsArray
{
let id = contacts["id"].stringValue
let name = contacts["name"].stringValue
println( "id: \(id) name: \(name)" )
self.dataArray.append(name)
}
self.tableView.reloadData()
})
}
task.resume()
}
Here i am taking name. If you want to display id as well, then create a model class for it.
Below is my ViewController code. The println in GetRequest prints the correct data that it receives from the HTTP GET request. At this point, tableData has 10 key-value pairs. However, if I put a break point after the call to GetRequest() in viewDidLoad(), tableData is empty and nothing is displayed in the tableView. Why is this? Where am I going wrong?
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource
{
#IBOutlet var tableView: UITableView!
var tableData: [String:String] = [:]
let textCellIdentifier = "TextCell"
func GetRequest(urlPath: String)
{
var LatestWaitTimes: [String:String] = [:]
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: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: &err)
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.array?.count
if let ct = count {
for index in 0...ct-1 {
let name = json[index]["CrossingName"].string
var wait = json[index]["WaitTime"].stringValue
if (wait == "-1")
{
wait = "No Info"
}
else
{
wait += " min"
}
println(name!+": "+wait)
LatestWaitTimes[json[index]["CrossingName"].stringValue] = wait as String?
}
}
self.tableData = LatestWaitTimes
})
task.resume()
}
override func viewDidLoad() {
super.viewDidLoad()
var apiInfo = GetWaitTimes()
GetRequest(apiInfo.BorderCrossingApi+"?AccessCode="+apiInfo.AccessCode)
self.tableView.delegate = self
self.tableView.dataSource = self
tableView.reloadData()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1;
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return tableData.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var cell = tableView.dequeueReusableCellWithIdentifier(self.textCellIdentifier) as! UITableViewCell
let thisEntry = self.tableData.values.array[indexPath.row]
cell.textLabel?.text = thisEntry+": "+tableData[thisEntry]!
return cell
}
func tableView(tableView: UITableView, didDeselectRowAtIndexPath indexPath: NSIndexPath) {
tableView.deselectRowAtIndexPath(indexPath, animated: true)
}
}
The problem is that GetRequest runs asynchronously. So you have to reloadData inside the completionHandler of dataTaskWithURL:
let task = session.dataTaskWithURL(url, completionHandler: {data, response, error -> Void in
// do all of your existing stuff here
dispatch_async(dispatch_get_main_queue()) {
self.tableData = LatestWaitTimes
self.tableView.reloadData()
}
})
task.resume()
You can remove the reloadData from within viewDidLoad.
Rearrange the orders of the method calls:
override func viewDidLoad() {
super.viewDidLoad()
self.tableView.delegate = self
self.tableView.dataSource = self
var apiInfo = GetWaitTimes()
GetRequest(apiInfo.BorderCrossingApi+"?AccessCode="+apiInfo.AccessCode)
tableView.reloadData()
}
Explanation: you set the delegate and dataSource before you GetRequest() so the dataSource won't be nil.
Try this it may help you
you can add a callback (for reload tablview) in GetRequest function and run the callback after parser json in completionHandler
Maybe When you set the delegate with tableview, tableData still be nil (waitting for http response)
this is my code .you can refer to
demand.loadDataFromServer(self.view, done: { () -> Void in
self.demands = demand.getDemandDataList()
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.tableView.reloadData()
})
})
func loadDataFromServer(view:UIView,done:(() -> Void)!){
var request:HttpRequest = HttpRequest(view:view)
request.GET(getDemandListURL, parameters: nil, success: { (dict) -> Void in
self.demandLists = dict["data"] as NSMutableArray
done()
}, failed: { (dict) -> Void in
}) { (error) -> Void in
}
}
I have trouble in loading the table view when parsing json files in swift.
Parsing the data is doing well. But no data are displayed in the table view.
This is the code :
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var redditListTableView: UITableView!
var tableData = []
#IBAction func cancel(sender: AnyObject) {
self.dismissViewControllerAnimated(false, completion: nil)
println("cancel")
}
#IBAction func done(sender: AnyObject) {
println("done")
}
override func viewDidLoad() {
super.viewDidLoad()
searchJsonFile("blabla.json")
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
println(tableData.count)
return tableData.count
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 0
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestCell")
let rowData: NSString = self.tableData[indexPath.row] as NSString
cell.textLabel.text = rowData as String
return cell
}
func searchJsonFile(searchFile: String) {
let urlPath = "http://data.../\(searchFile)"
let url = NSURL(string: urlPath)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithURL(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) {
println("JSON Error \(err!.localizedDescription)")
}
var results = [String]()
if let results1 = jsonResult["data"] as? NSDictionary{
for (key, value) in results1 {
if let eng = value["eng"] as? NSDictionary {
if let name = eng["name"] as? NSString{
results.append(name)
}
}
}
}
//println(results) OK!!!!
dispatch_async(dispatch_get_main_queue(), {
self.tableData = results
self.redditListTableView.reloadData()
})
})
task.resume()
}
}
You are returning 0 from numberOfSectionsInTableView - so you get no data displayed. You want 1 section -
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
If you are not having sections then just remove this function or comment
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 0
}
or else return 1