Jim H.
Jim H.

Reputation: 305

How to update TableViewCell with function having urlsession? Swift

I have a function that takes location coordinates and fetches weather data. This function is used at other places in the code.

Currently I'm using urlsession in cellForRowAt directly but dont want to repeat the code. Is there a way to call this weather function in TableViewController's cellForRowAt to update cells?

class Data {
    static func weather (_ coord:String, completion: @escaping...([String?]) -> (){

        let url = URL(string: "https://")

        let task = URLSession.shared.dataTask(with: url!) { data, response, error in

        let json = processData(data) //returns [String]?

        completion(json)
        }
        task.resume()


    }

    static func processData(_ data: Data) -> [String]? {

    }
}

In cellForRowAt, How to modify weather function to get values here before returning the cell, but original functionality of weather function taking completion should also stay?

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = ...
    Data.weather() ** ??? **
    cell.label.text = "" // value from weather
    return cell
}

Upvotes: 0

Views: 865

Answers (1)

gebirgsbärbel
gebirgsbärbel

Reputation: 2397

Triggering a network call in cellForRowAt indexPath is a bad idea. The method is called whenever the user scrolls through the table view. This could lead to a lot of network calls.

Instead you should:

  • Make the network call only when needed. For example you could do it in viewWillAppear. This method is called every time the app switches to your tableView
  • Store the result of your network call in a model. This could be something as simple as an array.
  • Redraw the tableView with reloadData
  • In cellForRowAt indexPath configure the cell with the data from the array.

Lets look at an example (it is incomplete, but should give you an idea, what to do):

class WeatherTableView: UITableView {
  var weatherData: [String]

  override func viewWillAppear(_ animated: Bool) {
    loadWeatherData()
  }

  private func loadWeatherData() {
    // I just set some data here directly. Replace this with your network call
    weatherData = ["Here comes the sun", "Rainy with chance of meatballs", "It's raining cats and dogs"]
    // Make sure the tableView is redrawn
    tableView.reloadData()
  }

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "weatherDataCell")
    cell.label.text = weatherData[indexPath.row]
    return cell
  }
}

Upvotes: 1

Related Questions