1

I have a UITableView and I need to populate with cells using data from some JSON that I get online. I have successfully acquired and parsed the data. The issue lies in the cells not being created with the proper data because they are created before the JSON Finishes loading and therefore cannot be displayed with the data. I know that you can easily use tableView.reloadData() and I run into another issue. I need to get the data downloaded before I even call any of the tableView methods.

The reason for this is because I want to return the number of cells based on how many cells are in the JSON. so something like jsoncells.count

This is my code so far: I had versions that kinda worked but they're gone since I've been tinkering with the code a little bit.

import UIKit

class TimelineViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

@IBOutlet weak var backgroundImageView: UIImageView!
var timelineCellDataArray = [[String:String]]()
override func viewDidLoad() {
    super.viewDidLoad()
    setupBackground(backgroundImage: #imageLiteral(resourceName: "Placeholder 1.jpeg"))
}

func setupBackground(backgroundImage: UIImage) {
    backgroundImageView.image = backgroundImage

    // Background Image Blur Effect:
    let backgroundImageBlurEffect = UIBlurEffect(style: .light)
    let backgroundImageBlurEffectView = UIVisualEffectView(effect: backgroundImageBlurEffect)
    backgroundImageBlurEffectView.frame = backgroundImageView.frame
    backgroundImageView.addSubview(backgroundImageBlurEffectView)
}

// Change View Controller To Profle View Controller
func setViewToProfileViewController() {
    print("H")
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let vc = storyboard.instantiateViewController(withIdentifier: "ProfileViewController") as! ProfileViewController
    self.navigationController?.pushViewController(vc, animated: true)
}



func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 4
}

var isLoad = true
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    var cell = tableView.dequeueReusableCell(withIdentifier: "TimelineCell", for: indexPath) as! TimelineCell

    // Json Parsing For Cell Populating
    let urlString = "https://www.jasonbase.com/things/QRkQ.json"
    let url = URL(string: urlString)
        URLSession.shared.dataTask(with: url!) { (data, response, error) in
            if error != nil  {

            } else {
                do {
                    let parsedData = try JSONSerialization.jsonObject(with: data!) as! [String:[[String:String]]]
                    self.timelineCellDataArray = parsedData["timelineCell"]!
                    DispatchQueue.main.async {
                        print("we")
                        switch self.timelineCellDataArray[indexPath.row]["cellType"] {
                        case "1"?:
                            cell = cell.createPostCell(cellToUse: cell)
                        case "2"?:
                            cell = cell.createPartyCell(cellToUse: cell)
                        case"3"?:
                            cell = cell.createFriendRequestCell(cellToUse: cell)
                        default:
                            break
                        }
                        tableView.reloadData()
                        self.isLoad = false
                    }
                } catch let error as NSError {
                    print(error)
                }
            }
            }.resume()
    print("WD")
    return cell
}

}

Here is my JSON https://www.jasonbase.com/things/QRkQ.json

6
  • Why are you reloading tableview inside the cellForRowAt delegate method? Don't create your dataset inside the cellForRowAt delegate method. Look up the verb 'to accuse' with your English dictionary before using it. Commented Feb 24, 2018 at 0:28
  • Well like I said i was just tinkering around to see if it worked but I did it so the table view would load the data and after the data is loaded it would reload the cells with the data Commented Feb 24, 2018 at 0:30
  • Loading data from cellForRowAt is a terrible idea. You need to load your data from viewDidLoad or some other appropriate place where the data is only loaded once, not for every cell. Commented Feb 24, 2018 at 0:31
  • Alright but how can I load that data before the cells are created because remember the cell data and the amount of Cells I want to create is going it be coming from the database Commented Feb 24, 2018 at 1:06
  • just a quick tip, your createPostCell shouldn't do all these things at once: be a non-static function for a cell, take in a cell as a parameter, and return a new cell. It is better coding practice to have createPostCell just be a non-static function that takes in the data that you use to populate the instance of that cell. Commented Feb 24, 2018 at 2:32

1 Answer 1

1

Do your JSON acquisition in viewDidLoad. You can then create a global variable (it seems you are using the variable called timelineCellDataArray) that stores your data that you append to every time you get new data from your database.

Once you finish getting all your data from the database, you call tableView.reloadData(). That way in your numberOfRowsInSection function, you can just return timelineCellDataArray.count. In your cellForRowAt function, you can just take the object in timelineCellDataArray[index.row] and populate your cell with this data.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much this is very helpful. So basically I get the data in viewdid load and one the data is done I reload view which will call all tableView functions again?
The only issue however is that I cannot do tableView.reloadData() from an external function
make an outlet to your tableView then you can reference it inside viewDidLoad

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.