Home > other >  Swift - Tableview reloads only after second tap of the tab bar
Swift - Tableview reloads only after second tap of the tab bar

Time:10-06

I've read 3 pages of google results and none worked for me, here's detailed description of the problem:

Every time I launch my app If I tap on the tab bar item that shows the vc that contains my table view it is empty. I have to go to another tab and return to it, just then my table view fetches. Spent 8h trying to fix it already.

Same exact VC shown with a button tap is displayed correctly and loads every time.

What i've already tried:

  • triple checked if I have: tableView.delegate = self tableView.dataSource = self
  • Tried moving the fetching to viewDidAppear or viewWillAppear, none worked.
  • Diagnosed it, number of sections is returned but number of rows = 0, cellForRowAt never executes on first tab bar click, even tho my posts are fetched correctly.
  • Tried fixing any constraints that exist, didn't work.

It simply seems like tableView.reloadData() doesn't work. I surrender, please help me!

my datasource methods:

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 100
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return posts.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = scansTableView.dequeueReusableCell(withIdentifier: "ScanCell") as! ScanTableViewCell
        let post = posts[indexPath.row]
        cell.scanView.layer.cornerRadius = 10
        let imageURL = URL(string: post.imageURL)
        cell.scanImage.kf.setImage(with: imageURL)
        cell.scanLabel.text = post.diagnose.description
        print("@@@")
        return cell
    }
    

my viewDidLoad() :

    override func viewDidLoad() {
        
        super.viewDidLoad()
        scansTableView.delegate = self
        scansTableView.dataSource = self
        scansTableView.separatorStyle = .none
        scansTableView.showsVerticalScrollIndicator = false
        let UUID = defaults.value(forKey: "UUID") ?? "Simulator"
        StartTestingViewController.posts(for: UUID as! String) { (posts) in
            self.posts = posts
        }
        
    }

where posts are just:

var posts = [Post]()

CodePudding user response:

You still haven’t provided a very clear picture. At a glance, though, I’d say you need to add a call to your table view’s reloadData() method inside the braces on your call to posts(for:completion:). (I’m guessing about the exact name of that function since you don’t include it.)

If your posts(for:completion:) invokes its completion handler on a background thread then you’ll need to wrap your call to reloadData() in a call to DispatchQueue.main.async() (Since TableView.reloadData() is a UIKit call and you can’t do UIKit calls on a background thread.)

The code might look like this:

StartTestingViewController.posts(for: UUID as! String) { (posts) in
    DispatchQueue.main.async {
        self.posts = posts
        self.tableView.reloadData()
    }
}

(I didn’t copy your whole viewDidLoad method, just the bit that calls your function that fetches posts.)

The UITableView.reloadData() method tells your table view “The number of sections/rows of data or their contents may have changed. Please re-ask your data source for contents and re-build your cells.” The table view will ask for the number of sections again, ask for the number of rows in each section, and ask for enough cells to fill the table view’s frame with cells.

If you don’t call reloadData() your table view has no idea that there is new data so it doesn’t reload itself.

I suspect that the reason that you can go another tab and come back and see your data is that the data has been loaded while you were on another tab, and so is available immediately. I’d have to see the exact details of your tab displaying code to be sure.

  • Related