The cellForRowAt
requires you to return a cell synchronously.
Customize your cell by passing the responsibility of each individual cell to load its contents, based on the request - thus reloading its own UI.
To illustrate:
This would be your cell (with your outlets already connected):
class FilesManagerCell: UITableViewCell {
@IBOutlet private weak var filenameLabel: UILabel!
@IBOutlet private weak var createdDateLabel: UILabel!
@IBOutlet private weak var fileSizeLabel: UILabel!
var filePath: URL! {
didSet {
fetchContents()
}
}
override func awakeFromNib() {
super.awakeFromNib()
//Here you should create the "Loading behavior", i.e:
self.filenameLabel.text = "Loading"
self.createdDateLabel.text = "Loading"
self.fileSizeLabel.text = "Loading"
}
private func fetchContents() {
APIClient.getFileInfo(patientId: filepath.lastPathComponent, onSuccess: { response in
DispatchQueue.main.async {
self.filenameLabel.text = response.file.fileName
self.createdDateLabel.text = response.file.creationDate
self.fileSizeLabel.text = response.file.fileSizeWithToken
}
}, onError: { (errorResponse, errorString) in
//Customize your error code, i.e:
DispatchQueue.main.async {
self.filenameLabel.text = "Error"
self.createdDateLabel.text = "Error"
self.fileSizeLabel.text = "Error"
}
})
}
}
And your tableView cellForRowAt
implementation:
//...
var files: [URL]!
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCell(withIdentifier: "FilesManagerCell", for: indexPath) as? FilesManagerCell {
let currentFile = files[indexPath.row]
cell.filePath = currentFile
}
return UITableViewCell()
}
//...
EDIT: There is no problem to delegate this responsibility to the cell itself, but be aware that when a cell is being reused, it will trigger a new fetchContents()
when setting the filePath
property, thus triggering a new API call - but there will be some data "inconsistency", because the while the fetch does not return, it will have the previous fetch contents. One solution to this could be resetting to "loading" state every time you set the filePath
, something like this:
var filePath: URL! {
didSet {
// Reset the current fields
self.filenameLabel.text = "Loading"
self.createdDateLabel.text = "Loading"
self.fileSizeLabel.text = "Loading"
// And then fetch the contents
fetchContents()
}
}