Асинхронный вызов API в UITableView cellForRowAt - PullRequest
0 голосов
/ 01 ноября 2018

У меня есть UITableView, чтобы показать список файлов. Каждое имя файла закодировано с определенной кодовой комбинацией, и чтобы получить реальное имя файла, я должен назвать свою серверную сторону с текущим именем файла.

Можно ли вызвать такую ​​операцию в функции делегата табличного представления cellForRowAt indexPath?

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]

            APIClient.getFileInfo(patientId: currentFile.lastPathComponent, onSuccess: { (response) in
                cell.filenameLabel.text = response.file.fileName
                cell.createdDateLabel.text = response.file.creationDate
                cell.fileSizeLabel.text = response.file.fileSizeWithToken               
                cell.filePath = currentFile
                return cell <- Here I get expected error

           }, onError: { (errorResponse, errorString) in                
        })

        }
        return UITableViewCell()

1 Ответ

0 голосов
/ 01 ноября 2018

cellForRowAt требует, чтобы вы возвращали ячейку синхронно.

Настройте свою ячейку, передав ответственность каждой отдельной ячейки за загрузку ее содержимого , основываясь на запросе - таким образом перезагрузив свой собственный пользовательский интерфейс.

Для иллюстрации:

Это будет ваша ячейка (с уже подключенными розетками):

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"
            }
        })
    }
}

И ваш tableView cellForRowAt Реализация:

//...
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()
}
//...

РЕДАКТИРОВАТЬ: Нет проблем с передачей этой ответственности самой ячейке, но имейте в виду, что когда ячейка повторно используется , она будет вызывать новый fetchContents() при установке свойства filePath , таким образом, вызывая новый вызов API - но будет некоторая «несогласованность» данных, потому что, пока выборка не возвращается, у нее будет предыдущее содержимое выборки. Одним из решений этой проблемы может быть сброс в состояние «загрузка» каждый раз, когда вы устанавливаете filePath, что-то вроде этого:

    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()
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...