Self.tableView.reloadData () does not work in Swift

I'm trying to learn Swift and the basics of iOS development at the same time, so bear with me. I have a TableViewController that first parses a local JSON file and displays its very simple data in TableViewCell and SectionHeaderViews. Inside the same TableViewController I have a TableViewController calling the JSON endpoint, which returns the data that I then set for the variables to get access to what I actually want to get to (the API structure is less desirable). So, I finally set the correct data as self.tableData and then called self.tableView.reloadData() but nothing happens. What gives?

 import UIKit class BusinessTableViewController: UITableViewController { var data: NSMutableData = NSMutableData() var tableData: NSArray = NSArray() @lazy var Business: NSArray = { let pathTCT = NSBundle.mainBundle().pathForResource("TCT", ofType: "json") let data = NSData.dataWithContentsOfFile(pathTCT, options: nil, error: nil) return NSJSONSerialization.JSONObjectWithData(data, options: nil, error: nil) as NSArray }() override func viewDidLoad() { super.viewDidLoad() navigationItem.titleView = UIImageView(image: UIImage(named: "growler")) tableView.registerClass(BeerTableViewCell.self, forCellReuseIdentifier: "cell") tableView.separatorStyle = .None fetchKimono() } override func numberOfSectionsInTableView(tableView: UITableView!) -> Int { // return Business.count return 1 } override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int { let biz = Business[section] as NSDictionary let results = biz["results"] as NSDictionary let beers = results["collection1"] as NSArray return beers.count } override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? { let cell = tableView!.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath!) as BeerTableViewCell if let path = indexPath { let biz = Business[path.section] as NSDictionary let results = biz["results"] as NSDictionary let beers = results["collection1"] as NSArray let beer = beers[path.row] as NSDictionary cell.titleLabel.text = beer["BeerName"] as String } return cell } override func tableView(tableView: UITableView!, titleForHeaderInSection section: Int) -> String! { let biz = Business[section] as NSDictionary return biz["name"] as String } override func tableView(tableView: UITableView!, viewForHeaderInSection section: Int) -> UIView! { let biz = Business[section] as NSDictionary let view = LocationHeaderView() view.titleLabel.text = (biz["name"] as String).uppercaseString return view } override func tableView(tableView: UITableView!, heightForHeaderInSection section: Int) -> CGFloat { return 45 } func fetchKimono() { var urlPath = "names have been changed to protect the innocent" var url: NSURL = NSURL(string: urlPath) var request: NSURLRequest = NSURLRequest(URL: url) var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false) connection.start() } func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) { // Recieved a new request, clear out the data object self.data = NSMutableData() } func connection(connection: NSURLConnection!, didReceiveData data: NSData!) { // Append the recieved chunk of data to our data object self.data.appendData(data) } func connectionDidFinishLoading(connection: NSURLConnection!) { // Request complete, self.data should now hold the resulting info // Convert the retrieved data in to an object through JSON deserialization var err: NSError var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary var results: NSDictionary = jsonResult["results"] as NSDictionary var collection: NSArray = results["collection1"] as NSArray if jsonResult.count>0 && collection.count>0 { var results: NSArray = collection as NSArray self.tableData = results self.tableView.reloadData() } } } 
+54
json ios objective-c uitableview swift
Jun 09 '14 at 2:14
source share
9 answers

You will need to reload the table in the UI thread via:

 //swift 2.3 dispatch_async(dispatch_get_main_queue(), { () -> Void in self.tableView.reloadData() }) //swift 5 DispatchQueue.main.async{ self.tableView.reloadData() } 

Continued: A simpler alternative to connection.start() is to use NSURLConnection.sendAsynchronousRequest(...) instead

 //NSOperationQueue.mainQueue() is the main thread NSURLConnection.sendAsynchronousRequest(NSURLRequest(URL: url), queue: NSOperationQueue.mainQueue()) { (response, data, error) -> Void in //check error var jsonError: NSError? let json: AnyObject? = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.allZeros, error: &jsonError) //check jsonError self.collectionView?.reloadData() } 

This does not allow you to flexibly track bytes, although, for example, you can calculate the download progress using bytesDownloaded / bytesNeeded

+154
Sep 21 '14 at 8:29
source share
— -

You only need to enter:

First select IBOutlet:

 @IBOutlet var appsTableView : UITableView 

Then in Action func:

 self.appsTableView.reloadData() 
+21
Jun 18 '14 at 13:04 on
source share

If your connection is in the background thread, then you should update the user interface in the main thread, like this

 self.tblMainTable.performSelectorOnMainThread(Selector("reloadData"), withObject: nil, waitUntilDone: true) 

As i mentioned here

Swift 4:

 self.tblMainTable.performSelector(onMainThread: #selector(UICollectionView.reloadData), with: nil, waitUntilDone: true) 
+4
Aug 6 '15 at 10:42
source share

In my case, the table was updated correctly, but setNeedDisplay () was not called for the image, so I mistakenly believed that the data was not reloaded.

+2
Dec 12 '16 at 17:51
source share

So the problem was that I was trying to improperly use @lazy, which resulted in my business variable being essentially constant and therefore incurable. Also, instead of loading local json, I now only load the data returned from the API.

 import UIKit class BusinessTableViewController: UITableViewController { var data: NSMutableData = NSMutableData() var Business: NSMutableArray = NSMutableArray() override func viewDidLoad() { super.viewDidLoad() navigationItem.titleView = UIImageView(image: UIImage(named: "growler")) tableView.registerClass(BeerTableViewCell.self, forCellReuseIdentifier: "cell") tableView.separatorStyle = .None fetchKimono() } override func numberOfSectionsInTableView(tableView: UITableView!) -> Int { return Business.count } override func tableView(tableView: UITableView?, numberOfRowsInSection section: Int) -> Int { if (Business.count > 0) { let biz = Business[section] as NSDictionary let beers = biz["results"] as NSArray return beers.count } else { return 0; } } override func tableView(tableView: UITableView?, cellForRowAtIndexPath indexPath: NSIndexPath?) -> UITableViewCell? { let cell = tableView!.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath!) as BeerTableViewCell if let path = indexPath { let biz = Business[path.section] as NSDictionary let beers = biz["results"] as NSArray let beer = beers[path.row] as NSDictionary cell.titleLabel.text = beer["BeerName"] as String } else { cell.titleLabel.text = "Loading" } return cell } override func tableView(tableView: UITableView!, viewForHeaderInSection section: Int) -> UIView! { let view = LocationHeaderView() let biz = Business[section] as NSDictionary if (Business.count > 0) { let count = "\(Business.count)" view.titleLabel.text = (biz["name"] as String).uppercaseString } return view } override func tableView(tableView: UITableView!, heightForHeaderInSection section: Int) -> CGFloat { return 45 } func fetchKimono() { var urlPath = "names have been removed to protect the innocent" var url: NSURL = NSURL(string: urlPath) var request: NSURLRequest = NSURLRequest(URL: url) var connection: NSURLConnection = NSURLConnection(request: request, delegate: self, startImmediately: false) connection.start() } func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) { // Recieved a new request, clear out the data object self.data = NSMutableData() } func connection(connection: NSURLConnection!, didReceiveData data: NSData!) { // Append the recieved chunk of data to our data object self.data.appendData(data) } func connectionDidFinishLoading(connection: NSURLConnection!) { // Request complete, self.data should now hold the resulting info // Convert the retrieved data in to an object through JSON deserialization var err: NSError var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary var results: NSDictionary = jsonResult["results"] as NSDictionary var collection: NSArray = results["collection1"] as NSArray if jsonResult.count>0 && collection.count>0 { Business = jsonResult tableView.reloadData() } } } 

Swift Docs on @lazy :

You should always declare a lazy property as a variable (with the var keyword), since its initial value cannot be obtained until the instance is initialized. Permanent properties must always be relevant before initialization is complete and therefore cannot be declared lazy.

+1
Jun 10 '14 at 15:16
source share

Besides the obvious reloadData from the UI / Main Thread (whatever Apple calls it), in my case I also forgot to update the SECTIONS information. Therefore, he did not find any new sections!

+1
Aug 18 '15 at 8:59
source share

All user interface calls must be asynchronous, everything you change in the user interface, such as updating a table or changing a text label, must be done from the main thread. using DispatchQueue.main will add your operation to the queue in the main thread.

Swift 4

 DispatchQueue.main.async{ self.tableView.reloadData() } 
0
Feb 28 '18 at 9:35
source share

You should only reload your TableView in the main thread. Otherwise, your application will crash or will be updated after some time. For each UI update, it is recommended that you use a main thread.

 //To update UI only this below code is enough //If you want to do changes in UI use this DispatchQueue.main.async(execute: { //Update UI self.tableView.reloadData()//Your tableView here }) //Perform some task and update UI immediately. DispatchQueue.global(qos: .userInitiated).async { // Call your function here DispatchQueue.main.async { // Update UI self.tableView.reloadData() } } //To call or execute function after some time and update UI DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { //Here call your function //If you want to do changes in UI use this DispatchQueue.main.async(execute: { //Update UI self.tableView.reloadData() }) } 
0
Dec 22 '18 at 6:59
source share

I also ran into the same problem that I did wrong, that I forgot to add

 tableView.delegate = self tableView.dataSource = self 

in the viewDidLoad () {} method. This may be one of the reasons that self.tableView.reloadData () is not working.

-one
May 15 '19 at 5:54
source share



All Articles