Каждый UITableViewCell имеет свою собственную задачу (вызов Webservice) и должен быть перезагружен после завершения своей задачи, задача вызывается каждые 30 секунд - PullRequest
0 голосов
/ 13 июня 2019

У меня есть UITableView, каждый UITableViewCell имеет свою собственную асинхронную задачу (вызов Webservice), ячейка должна быть уведомлена о завершении своей задачи, чтобы обновить метки, задача вызывается каждые 30 секунд. Я не хочу перерисовывать весь UITableView каждый раз.

Вот что я сделал до сих пор:

class ViewModel {
    var name, result: String
    var url: String

    init () {
        let timer = Timer.scheduledTimer(withTimeInterval: 30, repeats: true, block: self.startUpdating())
    }

    func startUpdating() {
        let dispatchQueue = DispatchQueue(label: "startUpdating", qos:.utility)
            dispatchQueue.async{
                self.callWebservice()
                // how can i notify my cell about the new changes
        }
    }

    func callWebservice(){
        //call web service and update name and result
    }
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    let vm = viewModels[indexPath.row]
    cell.textLabel = vm.name
    cell.detailTextLabel = vm.result
return cell
}

Ответы [ 2 ]

0 голосов
/ 13 июня 2019

Умным решением является наблюдение за ключевыми значениями.

  • Модель должна быть подклассом NSObject
  • Наблюдаемые свойства должны быть отмечены как @objc dynamic

    class ViewModel : NSObject {
        @objc dynamic var name, result: String
    ...
    
  • В Интерфейсном Разработчике установите стиль ячейки на custom, добавьте две метки и при необходимости установите ограничения AutoLayout

  • Создайте новый UITableViewCell подкласс, назовите его ResultCell и добавьте две метки и два свойства наблюдения

    class ResultCell: UITableViewCell {
    
        @IBOutlet weak var nameLabel: UILabel!
        @IBOutlet weak var resultLabel: UILabel!
    
        var nameObservation : NSKeyValueObservation?
        var resultObservation : NSKeyValueObservation?
    }
    
  • В Интерфейсном Разработчике установите класс пользовательской ячейки на ResultCell и подключите метки к пользовательской ячейке

  • В контроллере в cellForRow добавить наблюдателей

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! ResultCell
        let vm = viewModels[indexPath.row]
        cell.nameLabel!.text = vm.name
        cell.resultLabel!.text = vm.result
        cell.nameObservation = vm.observe(\.name, changeHandler: { (model, _) in
            cell.nameLabel!.text = model.name
        })
        cell.resultObservation = vm.observe(\.result, changeHandler: { (model, _) in
            cell.resultLabel!.text = model.result
        })
        return cell
    }
    
  • И вы должны удалить наблюдателей в didEndDisplaying

    override func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
         let resultCell =  cell as! ResultCell
         resultCell.nameObservation = nil
         resultCell.resultObservation = nil
    }
    

Преимущество заключается в том, что любое изменение name и result в модели будет обновлять ячейку, когда она появится на экране.

0 голосов
/ 13 июня 2019

Вы можете обновить одну конкретную ячейку вместо перезагрузки всего TableView.

yourTableView.beginUpdates()
yourTableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
yourTableView.endUpdates()
...